JavaFX: FXML: 如何使子元素扩展其大小以适应父面板?

29

我成功加载了一个子FXML(子UI)到父FXML(主菜单UI)下。我创建了一个ID为"mainContent"的AnchorPane,这个面板绑定在4个方向上,并会随着舞台(stage)的变化而改变大小。

子窗口将加载到"mainContent" AnchorPane中。但是,我不知道如何让子窗口随其父窗口"mainContent"一起改变大小。

我的子UI是这样调用的。

@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());
    }
}
为了进一步说明我的问题,请看我的截图。红色方块是孩子。黄色方块是MainMenu父项的“mainContent”AnchorPane。

这个面板绑定了4个边缘,并根据舞台的变化而改变。 你怎么做到的? - Tomi
6个回答

58
如果您将AnchorPane类的static方法setTopAnchor(child, value)setBottomAnchor(...)setLeftAnchor(...)setRightAnchor(...)设置为0.0,则子节点Node会被拉伸到父AnchorPane的完整扩展。
文档链接:AnchorPane
编辑:在文档链接中,您还可以看到如何在Java代码中设置这些值。
FXML示例:
<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>

嗨,Sascha B,当添加一个按钮时。例如。<AnchorPane fx:id="mainContent" ...> <AnchorPane fx:id="mainContent" ...> <StackPane fx:id="subPane" AnchorPane.topAnchor="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" > Button fx:id="button" layoutX="172.0" layoutY="195.0" onAction="#ingresarLogin" prefHeight="35.0" prefWidth="87.0" text="Ingresar" /> </StackPane> </AnchorPane>这样是正确的吗?......谢谢 - Marco R
2
这个被接受的答案对我没用。它是横向填充而不是纵向填充。不明白为什么这么简单的概念很难实现。 - user3217883
这样做不是正确的。使用案例涉及获取父节点和祖先节点以调整其后代节点,而不是相反。请参见我的答案。 - mike rodent

33
如果您有一个名为Region的类,它是Node的子类,包括AxisChartControlPane(这可能包括您想要加载的任何内容),您可以将子元素的大小与父元素中的空间绑定,类似于他们在此处所做的方式。现在,任何对父元素大小的未来调整都将反映在子元素中。
Region n = (Region)loader.load();
mainContent.getChildren().add(n);
n.prefWidthProperty().bind(mainContent.widthProperty());
n.prefHeightProperty().bind(mainContent.heightProperty());

不知道这是从哪个版本的JavaFX开始的,但对我来说设置prefWidth/Height没有任何作用,我必须使用minHeight。 - CodeClown42
很不幸,当使用AnchorPane时,此解决方案无法正常工作:当扩展窗格时,子级会增长到新大小,而无法缩小大小。 - voodoo_patch

2
根据您界面的结构,我建议您使用BorderPane作为父容器。请不要直接在BorderPane容器中使用AnchorPane。以下是我的建议:
- BorderPane-Top = "您的菜单" - BorderPane-Center = 另一个容器(可以是SplitPane、另一个BorderPane等,但我认为不应该是AnchorPane,但如果您愿意可以尝试) - BorderPane-Bottom = 另一个容器(可以是带有按钮或信息通知标签的hbox等)

1

我认为被接受的回答不是正确的。在 AnchorPane 中设置锚点会执行文档中所述的操作(setBottomAnchor):

如果设置了,锚定面板将保持子项的大小和位置,使其底部始终相对于锚定面板的底部内容边缘偏移该量。

但这并不是需要的结果。想要的是安排子级和父级具有相同的大小。

从我的实验中重要的一点是要认识到,父节点 Node 会接受和适应其子节点/子项的宽度和高度(首选宽度?首选高度?)... 如果你告诉它如何做。换句话说,机制的工作方向与您可能认为的相反:父级可以被告知适应子级,而不是子级适应父级。

使用 SceneBuilder 包含 ScrollPaneTextAreaAnchorPane 中的 HBox,可以实现问题所需的效果。

  <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>

请注意,没有使用锚点,并且最重要的是ScrollPane和AnchorPane没有“首选宽度”设置。
在SceneBuilder中,需要调整ScrollPane和AnchorPane的设置。在右侧面板/展开菜单下选择“布局:...”,选择ScrollPane,并将“Pref Width”设置为“USE_COMPUTED_AREA”。然后选择AnchorPane并执行相同的操作。最后,选择TextArea并将其设置为您的选择,例如在我的情况下为800(像素)。显然,如果您想要更复杂的设置,可以在代码中对此进行调整。
然后,您将看到TextArea的父级Node(AnchorPane)和祖父级Node(ScrollPane)会自动调整以适应TextArea。
请注意,HBoxprefWidth设置将被忽略。像HBox这样的容器通常会自适应其子元素,只有当您将其maxWidth设置为与其子元素的要求不兼容的值时,才会应用该约束条件。
如果您将一个孙节点NodeprefWidth设置为800,则可以假设在正常情况下计算出祖父级别的ScrollPane的宽度:这将涉及到所有三个组件中边框、填充、边距等设置。请注意类Region中的protected方法computePrefWidth,旨在供子类覆盖,这可能会很有用。
此外,在ScrollPane的情况下,垂直和/或水平滚动条的存在与否是很重要的,因为它们会随时出现。如果您在TextArea上设置了wrapTexttrue,您可能希望从不会出现水平滚动条。我的实验似乎表明,您还需要将ScrollPanefitToWidth属性设置为true

0

你可以尝试设置prefWidth。我不知道为什么,但似乎它会获取在SceneBuilder中引用newPane到AnchorPane后设置的prefWidth。

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

0

方法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);

另一种方法;

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);

方法2的详细信息链接: JavaFX面板内部面板自动调整大小


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接