JavaFX在没有控制器的fxml中包含fxml [英] JavaFX include fxml in fxml without controller

查看:310
本文介绍了JavaFX在没有控制器的fxml中包含fxml的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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



一切都运行正常,但我在单独的控制器和单独的fxml文件中为onActions设置了mainmenu及其所有功能。



我已经尝试了

p>

 < fx:include source =Menubar.fxml/> 

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



startpage.fxml使用



<获取其控制器Startpage pre> FXMLLoader loader = new FXMLLoader(getClass()。getResource(../ fxml / startpage.fxml));
loader.setController(new Startpage(m));
Pane mainPane = loader.load();

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

解决方案

我认为你需要使用 controllerFactory 在加载器中实现你想要的东西。当您使用 controllerFactory 时,您在FXML文件中指定控制器的类名,但控制器工厂允许您控制映射到对象的方式(因此您可以仍构建它传递模型等)。为 FXMLLoader 指定 controllerFactory 时,该工厂还用于为任何<$ c $创建控制器c>< fx:include> 你在FXML文件中有的。



最后,请注意你可以注入控制器将fxml文件包含在mainfxml文件中,如嵌套控制器部分



因此,如果startpage.fxml如下所示:

 <! - 进口等 - > 
< BorderPane fx:controller =com.example.Startpage...>
< top>
< fx:include source =Menubar.fxmlfx:id =menubar/>
< / top>
<! - etc ... - >
< / BorderPane>

和Menubar.fxml看起来像

 <! - 进口等 - > 
< MenuBar fx:controller =com.example.MenubarController...>
<! - etc ... - >
< / MenuBar>

然后你可以用以下方式控制控制器类的实例化:

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

型号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 {
// controllerFactory的默认行为:
try {
return type.newInstance();
} catch(Exception exc){
exc.printStackTrace();
抛出新的RuntimeException(exc); //致命,只是保释......
}
}
};

loader.setControllerFactory(controllerFactory);

Pane mainPane = loader.load();

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

 公共类Startpage {

public final Model m;

//注意这个字段的名称必须是xController,
//其中x是< fx:include>上设置的fx:id:

@FXML
private final MenubarController menubarController;

公共首页(型号m){
this.m = m;
}

// ...
}

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


I'm programming an application with javafx. It's a "multiscreen" application with a mainmenu from where I can switch my scene.

My scenes are defined in different fxml files.

Because I try to use the mvc pattern I don't set the controller in the fxml files, I use setController on the FXMLloader.

Everything is working fine but I have the mainmenu and all its functions for the onActions in separate controller and in separate fxml file.

I've tried it with

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

and created a controller for the fxml file, when I set the controller in the fxml file I can't compile the source. How do I set the controller for the included fxml file?

startpage.fxml gets its controller "Startpage" with

FXMLLoader loader = new FXMLLoader(getClass().getResource("../fxml/startpage.fxml"));
        loader.setController(new Startpage(m));
        Pane mainPane = loader.load();

startpage.fxml includes menubar.fxml, how to set a controller for the menubar controls now? Or how to include the menubarController easily in every other controller?

解决方案

I think you need to use a controllerFactory in the loader to achieve what you want here. When you use a controllerFactory, you specify the classname of the controller in the FXML files, but the controller factory allows you to control how that is mapped to an object (so you can still construct it passing in a model, etc). When you specify a controllerFactory for an FXMLLoader, that factory is also used to create the controllers for any <fx:include>s that you have in the FXML file.

Finally, note that you can inject the controller for the included fxml file into the "main" fxml file, as documented in the "Nested controllers" section of the FXML documentation.

So if startpage.fxml looks like this:

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

and Menubar.fxml looks like

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

Then you can control the instantiation of the controller classes with:

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();

Now you actually have references to both controllers in your application code, if you need, but you can also do

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 ;
    }

    // ...
}

So the main controller now has a reference to the menu bar controller.

这篇关于JavaFX在没有控制器的fxml中包含fxml的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆