java - 访问自定义 FXML 组件初始化中的子组件

标签 java javafx

如果我有一个像这样的自定义 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 时访问堆栈 Pane 的子级,以便我可以设置顶级菜单的其他菜单控件(我已从本示例中删除了它)。 FXMLLoader 不应该在调用 init 方法之前填充 Controller (MenuWidget)的所有属性吗?

编辑:发现 init 在构造函数完成之前被调用,因此尝试将 init 代码移动到构造函数中(在 fmxmlLoader.load() 调用之后),但它仍然不起作用。

最佳答案

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类没有定义 read-only list property命名menus 。如果你想使用<menus> ,并且您希望将该列表的元素添加到 menus 的子级中堆栈 Pane ,然后修改您的 MenuWidget类(class):

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 - 将其他 FXML 文件直接放入 MenuWidget FXML 文件,而不是您当前正在执行的操作。这样您就可以将 Controller 和/或 View (请参阅 nested controllers )注入(inject) MenuWidget 中。类(class)。我也不确定是否使用 fx:root根据您向我们展示的内容,在这种情况下是完全有保证的。继承自VBox似乎没有给您的代码添加任何好处(即您没有添加任何功能) - 特别是因为您只向其中添加一个子项(然后向该子项添加子项)。也许标准的 FXML 文件 + Controller 会更合适。

关于java - 访问自定义 FXML 组件初始化中的子组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60106519/

相关文章:

java - 如何使用不同参数运行 Gradle 任务

java - 如何自动生成一定范围内的重叠整数

java - 从命令行使用特定插件的特定路径运行 Maven

java - 在 Hbox 中找到按下的节点的位置

JavaFX 3D 着色面...再次

java - 无法让 Eclipse 与 Java FX 一起运行

JavaFX 和网络

java - 静态方法如何从调用 Activity 获取上下文?

java - 来自 Apache 2.2 服务器的 CONNECTION_REFUSED(到 weblogic 10.3.6 服务器的 channel )

java - 如何将字符串格式化为数字 (123) 456-7890