I have a BorderPane containing a Canvas, with the Canvas' height and width properties bound to the properties of the BorderPane. The BorderPane in turn is the root of a Scene.
This all works fine. If I resize the window, the BorderPane's size changes to match the size of the Scene, and the Canvas changes to match the size of the BorderPane.
However, if I introduce another BorderPane, it stops working: the inner BorderPane, and the Canvas, will grow as the Scene and outer BorderPane grow, but when I shrink the window, they don't shrink.
Working: Not working:
┌──────────────┐ ┌────────────────┐
│ Scene │ │ Scene │
│┌────────────┐│ │┌──────────────┐│
││ BorderPane ││ ││ BorderPane ││
││┌──────────┐││ ││┌────────────┐││
│││ Canvas │││ │││ BorderPane │││
││└──────────┘││ │││┌──────────┐│││
│└────────────┘│ ││││ Canvas ││││
└──────────────┘ │││└──────────┘│││
││└────────────┘││
│└──────────────┘│
└────────────────┘
The code that works:
BorderPane parent = new BorderPane();
Canvas canvas = new Canvas();
canvas.widthProperty().bind(parent.widthProperty());
canvas.heightProperty().bind(parent.heightProperty());
parent.setCenter(canvas);
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
The code that doesn't work:
BorderPane inner = new BorderPane();
Canvas canvas = new Canvas();
canvas.widthProperty().bind(inner.widthProperty());
canvas.heightProperty().bind(inner.heightProperty());
inner.setCenter(canvas);
BorderPane outer = new BorderPane();
outer.setCenter(inner);
Scene scene = new Scene(outer);
stage.setScene(scene);
stage.show();
I added some logging to confirm the problem:
# scene, outer pane, inner pane, and canvas growing
outer width: 1364.0 -> 1374.0
scene width: 1364.0 -> 1374.0
outer height: 339.0 -> 342.0
scene height: 339.0 -> 342.0
canvas width: 1364.0 -> 1374.0
inner width: 1364.0 -> 1374.0
canvas height: 339.0 -> 342.0
inner height: 339.0 -> 342.0
# scene and outer pane shrinking, canvas and inner not
outer width: 1374.0 -> 1327.0
scene width: 1374.0 -> 1327.0
outer height: 342.0 -> 330.0
scene height: 342.0 -> 330.0
outer width: 1327.0 -> 1290.0
scene width: 1327.0 -> 1290.0
outer height: 330.0 -> 326.0
scene height: 330.0 -> 326.0
Obviously in this toy example I can just remove the intermediate BorderPane, but what if I want to make a reusable, resizable component wrapping that Canvas? How can I make sure it's always resized with the parent? And what's the deal with nested BorderPanes, anyway?
Canvas
is a non-resizable node. This means it's size is a lower bound for the min
size of it's parent.
If you use the BorderPane
as scene root, resizing the window forces the scene to be resized and resizing the scene forces the scene root to be resized to fit the window. For this reason the parent of the Canvas
shrinks below it's min
size and the Canvas
shrinks too.
If you shrink a BorderPane
below it's min
size, it does not force it's resizable children to resize below their min
sizes but sets their sizes to the min
size instead. This way a BorderPane
wrapped in a BorderPane
is never forced to shrink below the size of the Canvas
and the Canvas
never shrinks.
You can fix this by setting the managed
property of the Canvas
to false
which results in the Canvas
not being considered when calculating the min
size. (Note that unmanaged children are not considered for layout at all. You should therefore wrap the Canvas
in a Pane
as the only child to prevent undesired effects on siblings.)
Canvas canvas = ...
canvas.setManaged(false);
Pane canvasParent = new Pane(canvas);
canvas.widthProperty().bind(canvasParent.widthProperty());
canvas.heightProperty().bind(canvasParent.heightProperty());
// TODO: put canvasParent in the scene