【发布时间】:2020-02-07 03:00:07
【问题描述】:
如果我有这样的自定义 JavaFX 组件(例如):
public class MenuWidget extends VBox implements Initializable {
@FXML
StackPane menus;
public MenuWidget() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/resources/MenuWidget.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println(menus.getChildren().size());
}
}
使用此 FXML:
<fx:root type="javafx.scene.layout.VBox" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml/1">
<StackPane fx:id="menus">
<padding>
<Insets top="5" left="5" bottom="5" right="5"></Insets>
</padding>
</StackPane>
</fx:root>
我在另一个 FXML 文件中使用这样的自定义组件:
<MenuWidget>
<menus>
<fx:include source="FirstMenu.fxml" />
<fx:include source="SecondMenu.fxml" />
</menus>
</MenuWidget>
为什么 MenuWidget 中的 Initialize() 方法会打印 0?本质上,我需要在构建 MenuWidget 时访问堆栈窗格的子项,以便我可以设置顶级菜单的其他菜单控件(我已从本示例中删除)。 FXMLLoader 不应该在调用 init 方法之前使用其所有属性填充控制器(MenuWidget)吗?
编辑:发现在构造函数完成之前调用了 init,因此尝试将 init 代码移动到构造函数中(在 fmxmlLoader.load() 调用之后),但它仍然不起作用。
【问题讨论】:
-
更好的解决方案可能是将构造函数代码移动到
initialize,完成后,再次执行 println 看看会发生什么 -
好主意!试过了,现在又发现了另一个问题。首先,我遇到了一个强制错误(它想将其中一个子菜单强制到 StackPane)。然后我将
标签添加到 并得到“父元素不支持属性元素”。 -
您的
MenuWidget类没有定义任何名为menus的列表属性,因此FXML 文件中的<menus>元素应该会导致错误。 -
啊,我明白了。我想将子菜单添加为 StackPane 的子菜单(MenuWidget 类中有一个 StackPane 属性)。由于
是 FXML 中的“默认”属性,我认为将它们添加到 中会将它们作为子项添加到 StackPane 菜单属性中。这样不行吗? -
如答案中所述,
MenuWidget.initialize()在加载MenuWidget.fxml的过程中被调用,这发生在MenuWidget构造函数调用期间(在将项目添加到菜单列表之前)。您的initialize方法可以向menus.getChildren()添加一个侦听器,并在添加项目时更新您需要更新的任何内容(但请注意,您不能在这样的侦听器中修改相同的menus.getChildren()列表)。这可能根本不是正确的解决方案;如果没有更多关于您要达到的目标的详细信息,就很难知道。