【问题标题】:JavaFX include fxml in fxml without controllerJavaFX 在没有控制器的 fxml 中包含 fxml
【发布时间】: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 包含在每个其他控制器中?

【问题讨论】:

    标签: model-view-controller javafx controller fxml


    【解决方案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 场景中设置场景中的设置。我在我的主类中创建了一个模型,然后......问题开始了,如何在控制器之间共享模型。我环顾四周,发现一些听起来不错的解决方案,一个是设置控制器stackoverflow.com/a/14190310/3710098,但这个解决方案不适用于 fxml 包括 fxml.. 我现在站在这里..
    • 好吧,我的解决方案肯定就是这样做的:在“主”控制器和包含的 fxml 控制器之间共享一个模型。代码的哪些部分你不明白?
    猜你喜欢
    • 1970-01-01
    • 2016-08-20
    • 2013-12-25
    • 1970-01-01
    • 2013-07-22
    • 2013-03-04
    • 1970-01-01
    • 2012-09-14
    相关资源
    最近更新 更多