如果我有这样的自定义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时,我需要访问堆栈窗格的子元素,这样我就可以设置顶级菜单的其他菜单控件(我已经从本例中删除了该控件)。在调用init方法之前,FXMLLoader不应该用它的所有属性填充控制器( MenuWidget)吗?
编辑:知道init是在构造函数完成之前调用的,所以尝试将init代码移动到构造函数中(在fmxmlLoader.load()调用之后),但它仍然无法工作。
发布于 2020-02-07 03:53:57
MenuWidget类及其关联的FXML文件是完全独立的。您没有包含任何内容,也没有将任何子元素添加到StackPane中。换言之,这是:
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());
}
}加载以下内容:
<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>一旦完成该操作,就会调用initialize方法。在menus中没有添加任何内容,因此调用menus.getChildren().size()的结果当然是0。
在其他地方,您正在加载以下内容:
<MenuWidget>
<menus>
<fx:include source="FirstMenu.fxml" />
<fx:include source="SecondMenu.fxml" />
</menus>
</MenuWidget>这将导致MenuWidget被实例化,这涉及调用MenuWidget#initialize方法,,然后尝试将子元素添加到menus。换句话说,如果这是有效且工作的FXML,那么在创建和初始化实例之后,将添加MenuWidget子实例。
但是,<menus>元素应该会导致应用程序抛出异常。MenuWidget类没有定义名为menus的只读列表属性。如果要使用<menus>,并且希望将该列表中的元素添加到menus堆栈窗格的子级,则将MenuWidget类修改为:
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());
}
// add read-only list property (the "property" is read-only, not
// the list itself) named "menus"
public final ObservableList<Node> getMenus() {
return menus.getChildren();
}
}但这似乎在概念上是错误的(至少对我来说是这样)。我不太清楚您想要做什么,但也许您应该将fx:include-ing其他FXML文件直接放到MenuWidget FXML文件中,而不是您当前正在做的事情。这样,您就可以将控制器和/或视图(参见嵌套控制器)注入到MenuWidget类中。根据您向我们展示的内容,我也不确定在本例中是否完全有理由使用fx:root。从VBox继承似乎并没有给您的代码添加任何好处(也就是说,您没有添加任何功能),因为您只是向它添加一个子(然后向该子子程序添加子)。也许一个标准的FXML文件+控制器会更合适。
https://stackoverflow.com/questions/60106519
复制相似问题