6
votes

I would like to create following scene:

+-----------------------------------------------+
|ROOT (=BorderPane)                             |
|                                               |
| +-------------------------------------------+ |
| |TOOL BAR                                   | |
| |(north)                                    | |
| +-------------------------------------------+ |
|                                               |
| +-------------------------------------------+ |
| |MyConfigurationComponent extends BorderPane| |
| |(center)                                   | |
| |  +-------------------------+  +---------+ | |
| |  |ScrollPane               |  |         | | |
| |  |(center)                 |  |         | | |
| |  | +---------------------+ |  |         | | |
| |  | |                     | |  |         | | |
| |  | |                     | |  |  SIDE   | | |
| |  | |       CANVAS        | |  |  PANE   | | |
| |  | |                     | |  | (right) | | |
| |  | |                     | |  |         | | |
| |  | |                     | |  |         | | |
| |  | +---------------------+ |  |         | | |
| |  |                         |  |         | | |
| |  +-------------------------+  +---------+ | |
| |                                           | |
| +-------------------------------------------+ |
|                                               |
+-----------------------------------------------+

Expectation

I would like to make the ScrollPane as big as possible. That means that ScrollPane should grow and fill entire area, whatever the size of scene is.

Since both the TOOL BAR and SIDE PANE have fixed (preferred) width and height, I thought that the ScrollPane will stretch and fill the whole remaining area.

Actual behavior

But it doesn't. The ScrollPane somehow magically sets its minimum size to something about 40x40. The height is stretched to match height of SIDE PANEL, but the width is still the same and nothing seems to be able to change it.

In fact, the only one thing, which makes the ScrollPane bigger was to explicitly set minWidth to some value (i.e. 400). But this does not solve issue about the ScrollPane's auto resisize.

When I set background color to MyConfigurationComponent, I can see that background color fills whole area as expected (so the problem is not with MyConfigurationComponent). It looks like its center child (ScrollPane) is rendered as left, its right child (SIDE PANEL) as center, because all the remaining area on the right side remains blank (but with the background, so it is still MyConfigurationComponent!).

What have I tried

  • set min, pref, and max sizes of ScrollPane to particular values
  • bind prefered size to parent's size
  • set fitToWidth and fitToHeight to true
  • wrap ScrollPane with AnchorPane with anchor to all four sides
  • wrap ScrollPane with VBox and set priority to allways

Current workaround

Bind the width of MyConfigurationComponent minus width of SIDE PANEL to ScrollPane. Wrong in many ways.

Code

ROOT.fxml

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.upol.fapapp.cfa.gui.frame.FxCFAConfigFrameController">
   <top>
            <ToolBar>
                <Button text="Some button" />
            </ToolBar>
   </top>
   <center>
      <MyConfigurationComponent fx:id="configComp" />
   </center> 
</BorderPane>

MyConfigurationComponent.fxml

<BorderPane xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
    <center>
        <ScrollPane fx:id="scrollPane">
            <content>
                <Canvas width="2000" height="2000" />
            </content>
        </ScrollPane>
    </center>
    <right>
        <VBox prefWidth="100.0" BorderPane.alignment="CENTER_RIGHT">
            <children>
                <Label text="Colors" />
                <ComboBox fx:id="cmbColors" prefWidth="100.0" />    
                <!-- ... -->
                <Separator prefHeight="15.0" prefWidth="100.0" />
                <Button mnemonicParsing="false" text="Action 1" />
                <Button mnemonicParsing="false" text="Action 2" />
            </children>
        </VBox>
    </right>
</BorderPane>

Questions

  • BorderPane's center extends its size to fill content, isn't it?
  • Can this be somehow caused by BorderPane inside of BorderPane?
  • Is there better solution than 'my workaround'?
2
Is it possible to use AnchorPane instead of BorderPane as the parent to MyConfigurationComponent? That way you could use the FXML AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="100.0" AnchorPane.topAnchor="0.0" AnchorPane.bottomAnchor="0.0" in the opening ScrollPane tag, where .rightAnchor is assigned to the width of your "Side Panel" - j.seashell
From the javadoc: The top and bottom children will be resized to their preferred heights and extend the width of the border pane. The left and right children will be resized to their preferred widths and extend the length between the top and bottom nodes. And the center node will be resized to fill the available space in the middle. BorderPane isn't the right layout for the expected behavior. Use a HBox and set hgrow for the BorderPane and the side pane to ALWAYS and NEVER respectively. - fabian
I copied and pasted your FXML exactly as it is (doing the minimum to make it so I could run it; i.e. I replaced <MyConfigurationComponent> with <fx:include>, removed the controller, etc), and it worked as expected: the scroll pane filled the space not occupied by the toolbar or the VBox on the right side. So whatever is causing it to fail to work the way you want is somewhere else in your code. Expand the code in the question to a minimal reproducible example. - James_D
I suspect the problem lies in the way you are implementing the MyConfigurationComponent class. Normally if you use your own node subclass, and performing the layout for that in FXML, you would use this technique. But since you don't have <fx:root> in the FXML for MyConfigurationComponent, you are clearly doing something else. My guess is that is where the issue is. - James_D

2 Answers

0
votes

You can put this in your code, inside of the start method:

stage.widthProperty().addListener(event -> {
    scrollPane.setPrefWidth(stage.getWidth());
});

stage.heightProperty().addListener(event -> {
    scrollPane.setPrefHeight(stage.getHeight());
});

If that doesn't work, I'd recommend setting the BorderPane's width and height to the dimensions of the stage, too:

stage.widthProperty().addListener(event -> {
    scrollPane.setPrefWidth(stage.getWidth());
    borderPane.setPrefWidth(stage.getWidth());
});

stage.heightProperty().addListener(event -> {
    scrollPane.setPrefHeight(stage.getHeight());
    borderPane.setPrefHeight(stage.getHeight());
});