Search code examples
javafxborder

JavaFX rectangle is overwriting border


Given:

package pkg;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage stage) {
        var scene = new Scene(getView(), 640, 480);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }

    private Pane getView() {
        Pane pane = new Pane();
        Rectangle r = new Rectangle(0, 0, 300, 200);
        r.setFill(Color.RED);
        r.setStroke(Color.YELLOW);
        r.setStrokeWidth(10);
        pane.getChildren().add(r);
        pane.setBorder(new Border(new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
                new BorderWidths(2))));
        AnchorPane ap = new AnchorPane();
        ap.getChildren().add(pane);
        return ap;
    }
}

This renders as: enter image description here

Why is the rectangle stomping the border of its container? It appears the pane is sized to the size of the rectangle plus the stroke width.


Solution

  • This appears to be the expected result of the "absolute positioning of children" offered by Pane, which "does not perform layout beyond resizing resizable children to their preferred sizes." In particular,

    • The red rectangle's top left corner is at (0, 0).

    • The strokeType defaults to CENTERED, placing its top left corner at (0, 0), clipped to the left and above.

    • The black border shows the computed size, absent any layout.

    For comparison, the example below adds the rectangle and border to a StackPane, which lays out its children with Pos.CENTER alignment by default.

    Image

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.Border;
    import javafx.scene.layout.BorderStroke;
    import javafx.scene.layout.BorderStrokeStyle;
    import javafx.scene.layout.BorderWidths;
    import javafx.scene.layout.CornerRadii;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
        @Override
        public void start(Stage stage) {
            stage.setScene(new Scene(getView()));
            stage.show();
        }
    
        private Pane getView() {
            Rectangle r = new Rectangle(0, 0, 300, 200);
            r.setFill(Color.RED);
            r.setStroke(Color.YELLOW);
            r.setStrokeWidth(10);
            StackPane sp = new StackPane();
            sp.setBorder(new Border(new BorderStroke(Color.BLACK,
                BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(2))));
            sp.getChildren().add(r);
            return sp;
        }
    
        public static void main(String[] args) {
            launch();
        }
    }