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 文件中拥有的任何 <fx:include>
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 节点