JavaFX 在没有控制器的 fxml 中包含 fxml

Posted

技术标签:

【中文标题】JavaFX 在没有控制器的 fxml 中包含 fxml【英文标题】:JavaFX include fxml in fxml without controller 【发布时间】:2015-05-29 04:38:53 【问题描述】:

我正在使用 javafx 编写应用程序。 这是一个“多屏”应用程序,带有一个主菜单,我可以从中切换场景。

我的场景是在不同的 fxml 文件中定义的。

因为我尝试使用 mvc 模式我没有在 fxml 文件中设置控制器,所以我在 FXMLloader 上使用了 setController。

一切正常,但我在单独的控制器和单独的 fxml 文件中有主菜单及其 onActions 的所有功能。

我试过了

<fx:include source="Menubar.fxml"/>

并为 fxml 文件创建了一个控制器,当我在 fxml 文件中设置控制器时,我无法编译源代码。如何为包含的 fxml 文件设置控制器?

startpage.fxml 通过

获取其控制器“起始页”
FXMLLoader loader = new FXMLLoader(getClass().getResource("../fxml/startpage.fxml"));
        loader.setController(new Startpage(m));
        Pane mainPane = loader.load();

startpage.fxml包含menubar.fxml,现在如何为菜单栏控件设置控制器?或者如何轻松地将 menubarController 包含在每个其他控制器中?

【问题讨论】:

【参考方案1】:

我认为你需要在加载器中使用controllerFactory 来实现你想要的。当您使用controllerFactory 时,您在 FXML 文件中指定控制器的类名,但控制器工厂允许您控制如何将其映射到对象(因此您仍然可以在模型中构建它,等等)。当您为 FXMLLoader 指定 controllerFactory 时,该工厂还用于为您在 FXML 文件中拥有的任何 &lt;fx:include&gt;s 创建控制器。

最后,请注意,您可以将包含的 fxml 文件的控制器注入到“主”fxml 文件中,如 "Nested controllers" section of the FXML documentation 中所述。

所以如果 startpage.fxml 看起来像这样:

<!-- imports etc -->
<BorderPane fx:controller="com.example.Startpage" ... >
  <top>
    <fx:include source="Menubar.fxml" fx:id="menubar" />
  </top>
  <!-- etc ... -->
</BorderPane>

Menubar.fxml 看起来像

<!-- imports etc -->
<MenuBar fx:controller="com.example.MenubarController" ... >
  <!-- etc... -->
</MenuBar>

然后你可以控制控制器类的实例化:

FXMLLoader loader = new FXMLLoader(getClass().getResource("../fxml/startpage.fxml"));

Model m = ... ;

Startpage startpageController = new Startpage(m);
MenubarController menubarController = new MenubarController(m);

Callback<Class<?>, Object> controllerFactory = type -> 
    if (type == Startpage.class) 
        return startpageController ;
     else if (type == MenubarController.class) 
        return menubarController ;
     else  
        // default behavior for controllerFactory:
        try 
            return type.newInstance();
         catch (Exception exc) 
            exc.printStackTrace();
            throw new RuntimeException(exc); // fatal, just bail...
        
    
;

loader.setControllerFactory(controllerFactory);

Pane mainPane = loader.load();

现在,如果需要,您实际上在应用程序代码中都引用了这两个控制器,但您也可以这样做

public class Startpage 

    public final Model m ;

    // note the name of this field must be xController,
    // where x is the fx:id set on the <fx:include>:

    @FXML
    private final MenubarController menubarController ;

    public Startpage(Model m) 
        this.m = m ;
    

    // ...

所以主控制器现在有了对菜单栏控制器的引用。

【讨论】:

好的,我需要更多知识,我现在不明白你的答案。编辑。我希望它可以像“startpagecontroller extends menucontroller”之类的那样简单。我想我仍然会在每个控制器中保留菜单栏的所有方法以及 fxml 代码.. :/ 除非我知道您不了解哪些部分,否则我真的无能为力。每个 fxml 文件都有一个与之关联的控制器 instance。 fxml 文件可以为控制器指定一个 class。所以控制器工厂只是一个函数,它告诉FXMLLoader 如何从指定的类中获取控制器实例。复制方法或使一个控制器成为另一个控制器的子类都无济于事,因为您仍然有两个不同的控制器实例(因此它们不会引用相同的数据)。 对我来说最大的问题是理解您的解决方案(只是一个 java 初学者)和/或使您的示例适应我的代码。我将尝试解释一下为什么我需要这一切。首先,当我开始项目时,每个 fxml 文件都有自己的控制器,这很好,我可以将每个 fxml 包含在彼此中而不会丢失任何功能。例如,我在应用程序“createproject”中有一个页面,该页面包含一些文本字段并包含菜单栏。当我使用菜单项将页面(场景)切换到“settingsforcreateproject”时,我再次将菜单栏包含在新的 fxml 中。 看这里gist.github.com/Garog/ee979f4c50c76c554f86 一切都很好,比使用swing 或awt 工作更愉快,但是我需要场景b 中的场景a 中的数据,比如projectcreate 场景中设置场景中的设置。我在我的主类中创建了一个模型,然后......问题开始了,如何在控制器之间共享模型。我环顾四周,发现一些听起来不错的解决方案,一个是设置控制器***.com/a/14190310/3710098,但这个解决方案不适用于 fxml 包括 fxml.. 我现在站在这里.. 好吧,我的解决方案肯定就是这样做的:在“主”控制器和包含的 fxml 控制器之间共享一个模型。代码的哪些部分你不明白?

以上是关于JavaFX 在没有控制器的 fxml 中包含 fxml的主要内容,如果未能解决你的问题,请参考以下文章

如何使用不同的 fxml 文件创建多个 javafx 控制器?

无法在 javafx 中链接 fxml 和控制器文件变量 [重复]

动态访问/遍历/操作从控制器类外部的 FXML 创建的 JavaFX 节点

JavaFX 8 - 每个选项卡带有单独的 FXML 和控制器的选项卡和选项卡

设置root的JavaFx FXML加载文件问题

在 JavaFX FXML 控制器中实现构造函数