Question

I have managed to load a child fxml(sub UI) under a parent fxml (mainMenu UI). I have created an AnchorPane with id "mainContent". This pane is bound to 4 sides and changes in accords to the stage.

The child window will be loaded into the "mainContent" anchorpane. However, I can't figure out how to make the child to change along with its parent "mainContent".

My child UI is called like this.

@FXML
private void mnuUserLevel_onClick(ActionEvent event) {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("DBedit.fxml"));
    loader.setController(new DBeditEntityUserlevel());

    try {
           Node n = (Node)loader.load();
           mainContent.getChildren().add(n);
    } catch (IOException e){
           System.out.println(e.getMessage());
    }
}

To further illustrate my question, please see my snap shot. The red square is the child. The yellow square is the "mainContent" AnchorPane of the MainMenu parent.

enter image description here

Was it helpful?

Solution

If you set the static methods setTopAnchor( child, value ), setBottomAnchor( ... ), setLeftAnchor( ... ), setRightAnchor( ... ) of class AnchorPane to 0.0, the child Node will get stretched to the full extend of the parent AnchorPane.

Documentation Link: AnchorPane

edit: in the documentation link you can also see how you can set these values in your java code.

FXML example:

<AnchorPane fx:id="mainContent" ...>
<StackPane fx:id="subPane" AnchorPane.topAnchor="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" ></StackPane>
</AnchorPane>

OTHER TIPS

If you have a Region, which is a subclass of Node that includes Axis, Chart, Control, and Pane (this probably includes anything you might want to load), you can bind the child's size to the space in the parent similar to how they did here. Now any future adjustments of the parent's size will be reflected in the child.

Region n = (Region)loader.load();
mainContent.getChildren().add(n);
n.prefWidthProperty().bind(mainContent.widthProperty());
n.prefHeightProperty().bind(mainContent.heightProperty());

With the look at the structure of your interface I guess you better use BorderPane as your parent container with this suggestion don't use AnchorPane directly inside the BorderPane container here is my suggestion you do:

->BorderPane-Top = "your menu"

->BorderPane-Center = another container (could be SplitPane, another BorderPane etc.. but not AnchorPane I guess but you can try if you want)

->BorderPane-Bottom = another container (could be hbox with buttons or label for info or notifications etc..)

I don't think the accepted answer is the right one. Setting the anchors in an AnchorPane does what it says in the documentation (setBottomAnchor):

If set, the anchorpane will maintain the child's size and position so that its bottom is always offset by that amount from the anchorpane's bottom content edge.

But that's not what is desired. It is to arrange things so that the child and parent are the same size.

The important thing to appreciate, from my experiments, is that a parent Node will accept and adapt to the width and height (preferred width? preferred height?) of its child/children... if you tell it to. In other words, the mechanism works in the contrary direction to the one you might assume: the parent can be told to adapt to the child, not the child to the parent.

With an HBox containing a ScrollPane containing an AnchorPane containing a TextArea, using SceneBuilder, this does what the question is looking for:

  <HBox prefHeight="100.0" prefWidth="200.0">
     <children>
        <ScrollPane prefHeight="100.0">
          <content>
            <AnchorPane>
                 <children>
                    <TextArea fx:id="logTextArea" prefWidth="800.0">
                    </TextArea>
                 </children>
              </AnchorPane>
          </content>
        </ScrollPane>
     </children>
  </HBox>

Note that there is no use of anchors, and above all that the ScrollPane and the AnchorPane have no "preferred width" setting.

In SceneBuilder, the thing to adjust here for the ScrollPane and the AnchorPane is in the right-hand panel/concertina, under "Layout: ...:" choose the ScrollPane, and set "Pref Width" to "USE_COMPUTED_AREA". Then choose the AnchorPane and do the same. Finally, choose the TextArea and set this to your choice, e.g. in my case 800 (pixels). Obviously this setting can be adjusted to something more sophisticated in your code if you want.

You will then see that the parent Node of the TextArea (AnchorPane) and grandparent Node (ScrollPane) adjust to accommodate the TextArea.

Note that the prefWidth setting of the HBox then gets ignored. It is the normal job of a container like an HBox to accommodate its descendants, and it would only be if you set its maxWidth to something incompatible with the requirements of its descendants that that constraint would then apply.

If you set a grandchild Node like this with a prefWidth of 800, I assume there is some way of calculating the width, under normal circumstances, of the grandparent ScrollPane: this will be something to do with settings of borders, padding, margins and the like, in all three components involved. Note the protected method in class Region, computePrefWidth, intended for subclasses to override, which may be of interest.

Plus, in the case of ScrollPane, the presence or absence of vertical and/or horizontal scrollbars, as and when these appear. If you set wrapText to true on the TextArea you might hope that a horizontal scrollbar will never appear. My experiments seem to show that you also need to set ScrollPane's fitToWidth Property to true.

You could try with setting prefWidth. I don't know why, but it seems like it takes the prefWidth which is set in SceneBuilder after referencing your newPane to your AnchorPane.

Node newPane = FXMLLoader.load(getClass().getResource("view/YourPane.fxml"));
List<Node> parentChildren = ((Pane)yourAnchorPaneId.getParent()).getChildren();
parentChildren.set(parentChildren.indexOf(yourAnchorPaneId), newPane);
yourAnchorPaneId.setPrefWidth(1800); // 1800 just example value for test
Main.primaryStage.setWidth(500); // 500 example value with which you wishe to start app

Method 1 :

// @FXML private AnchorPane pnlContainer;

FXMLLoader loader = new FXMLLoader(getClass().getResource("Demo.fxml"));

Node _node = loader.load();

_node.prefWidth(pnlContainer.widthProperty().doubleValue());
_node.prefHeight(pnlContainer.heightProperty().doubleValue());

// container child clear
pnlContainer.getChildren().clear();

// new container add
pnlContainer.getChildren().add(_node);

Alternative method;

FXMLLoader loader = new FXMLLoader(getClass().getResource("Demo.fxml"));

Node _node = loader.load();

AnchorPane.setTopAnchor(_node, 0.0);
AnchorPane.setRightAnchor(_node, 0.0);
AnchorPane.setLeftAnchor(_node, 0.0);
AnchorPane.setBottomAnchor(_node, 0.0);

// container child clear
pnlContainer.getChildren().clear();

// new container add
pnlContainer.getChildren().add(_node);

Method 2 detail link : JavaFX Panel inside Panel auto resizing

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top