JavaFX8 FXML控制器注入

3

在我的GUI应用程序中,我有两个视图:playlistView.fxmlvideoView.fxml。每一个都有自己的控制器。我希望playListView成为videoView布局的一部分,所以我使用:

<fx:include fx:id="idPlayListAnchorPane" source="playListView.fxml" />

要包含该文件。 运行良好,播放列表显示为videoView布局的一部分。

然后,我像这样将 idPlayListAnchorPane FXML变量注入到 VideoViewController 中:

@FXML
private AnchorPane idPlayListAnchorPane;    

这也可以实现。例如,我可以使用以下代码从 VideoViewController 中禁用 playListView 中的 idPlayListAnchorPane

idPlayListAnchorPane.setDisable(true);

为了获得playListViewController,我使用以下代码:
FXMLLoader loader = new FXMLLoader(Main.class.getResource("/designer/views/video/playListView.fxml"));
    PlayListViewController playListViewController = new PlayListViewController();
    loader.setController(playListViewController);
    try {
        AnchorPane playListView = (AnchorPane) loader.load();
    } catch (IOException e) {
    };

然后我可以调用例如:

playListViewController.init();    

来自videoViewController

但是init()方法在playListView ListView中创建了一些测试值(作为一个单独的应用程序进行测试,并且可以正常工作)。然而,这些测试值现在没有显示在ListView中。经过多个小时的简单问题是:为什么呢?


经过一些调查,我发现ListView中的onAction处理程序也不再触发,因此显然列表视图控制器和videoViewController之间没有“连接”。我认为最好的选择是使用fx:include,但忘记单独的控制器并将代码粘贴到第一个控制器中。 - Frank
不要这样做。你仍然会有两个控制器,它们只是来自同一个类。除了仍然存在如何在两个控制器实例之间通信的问题外,还将极其难以跟踪每个实例中初始化了哪些字段。(一个将具有从一个FXML初始化的字段,另一个将具有从另一个FXML初始化的字段。)只需使用文档中显示的标准机制即可。 - James_D
1个回答

7
您正在两次加载playListView.fxml文件:一次来自<fx:include>,一次是在代码中创建FXMLLoader并调用load()。由<fx:include>创建的节点层次结构(即AnchorPane及其所有内容)显示在您的GUI中;由FXMLLoader.load()调用创建的节点层次结构则不会显示。
由于您创建的控制器与未显示的节点层次结构相关联,因此您在控制器上调用的方法将不会对UI产生任何影响。
您可以使用文档中描述的Nested Controller技术,直接从包含的FXML中将控制器注入到您的VideoViewController中,而无需创建FXMLLoader以获取控制器实例。
要实现这一点,首先向您的playListView.fxml根元素添加fx:controller属性:

playListView.fxml:

<!-- imports etc -->
<AnchorPane fx:controller="com.mycompany.packagename.PlayListViewController">
    <!-- etc etc -->
</AnchorPane>

由于您在<fx:include ...>上定义了一个fx:id="idPlayListAnchorPane"属性,因此您可以通过使用一个带有@FXML注释的字段idPlayListAnchorPaneController(规则是将"Controller"附加到id后面)直接将控制器注入VideoViewController类中:

public class VideoViewController {
    @FXML
    private AnchorPane idPlayListAnchorPane;
    @FXML
    private PlayListViewController idPlayListAnchorPaneController ;

    // ...
}

现在,您只需根据需要在控制器上调用方法即可。

是的!谢谢詹姆斯。我在书籍“Pro JavaFX8”中找到了一个例子,并尝试了FXML注入,但无法使其工作。我微弱的尝试和你的工作版本之间的微妙差别在于,我使用了私有的PlayListViewController playListViewController,而应该是私有的PlayListViewController idPlayListAnchorPaneController。现在由于JavafX Oracle,事情变得更加清晰了;-) - Frank

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