我正在学习JavaFX,遇到一个涉及实例化控制器的问题,我似乎无法解决。本质上,我想知道是否可以执行以下操作之一:
<fx:include>
中包含FXML时,将参数传递给控制器的构造函数;或<fx:include>
的FXML文件时要使用的自定义控制器实例。请注意,这些问题是相关的。实际上,我问选项(2)的原因是因为它将解决选项(1)。
我的设置
我有以下“主要” FXML文件:
<!-- XML declaration, imports, etc. removed for brevity --> <BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"> <!-- ... --> <center> <!-- Note that PageSwitcher is a custom control that is capable of switching between pages — you should be able to ignore it here. --> <PageSwitcher fx:id="mainPageSwitcher" currentPageIndex="0"> <!-- ... --> <fx:include source="dashboard.fxml" fx:id="dashboard" /> </PageSwitcher> </center> </BorderPane>
它具有关联的控制器
MainPaneController
。我不会在这里显示它,但如有必要,我可以显示。
您可能已经注意到我的主FXML文件在其fx:controller
上没有BorderPane
属性,尽管事实是我说它具有关联的控制器。这是因为,当我在主目录中加载主FXML页面时,我选择了此方法,而不是允许FXMLLoader
为我创建一个控制器(因此,没有办法将参数传递给控制器类的构造函数)。应用程序类(即扩展Application的类),以创建我自己的MainPaneController
类实例。您可以看到我的主应用程序类的start()
方法:
@Override public void start(Stage primaryStage) throws IOException { FXMLLoader mainPaneLoader; MainPaneController mainPaneController; Parent mainPane; // Initialize the project manager. projectManager = new ProjectManager(primaryStage); // Initialize the main pane loader. mainPaneLoader = new FXMLLoader(); // Initialize the main pane controller. mainPaneController = new MainPaneController(projectManager); // Load the main pane. mainPaneLoader.setController(mainPaneController); mainPaneLoader.setLocation(getClass().getResource(MAIN_PANE_FXML_PATH)); mainPane = mainPaneLoader.load(); Scene mainScene; // Create the main scene and add it to the primary scene. mainScene = new Scene(mainPane); primaryStage.setScene(mainScene); // Initialize the primary stage. primaryStage.setTitle(APPLICATION_TITLE); // Show the primary stage. primaryStage.show(); }
请注意,上面定义并传递到主窗格控制器的构造函数中的“项目管理器”对象实际上是整个问题的主要动机;它是(除了传递到主控制器之外)需要传递给使用
<fx:include>
包含在主FXML文件中的FXML文件的控制器的对象。现在,这种创建我自己的控制器实例并将其提供给
FXMLLoader
的方法对我来说非常有效。它使我可以轻松地将参数传递给控制器的构造函数,而不会引起任何混乱。但是,只有当我有FXMLoader
对象将控制器实例提供给它时,它才起作用。
在other
情况下,当我使用<fx:include>
从主FXML文件中包含一个FXML文件时,JavaFX为我创建了控制器,而我没有办法(1)将参数传递给控制器的构造函数,或(2)使用我自己的控制器实例。我尝试过的事情
[在研究此问题时,我发现this StackOverflow question似乎与该问题至少有一些联系。从中,我了解了FXMLLoader.setControllerFactory()
,乍一看似乎可以解决此问题。但是,为了使用它,我被迫使用一些相当混乱的反射来检查类型的构造函数是否可以接受我的对象,然后使用more反射来创建控制器,同时希望没有错误发生。因为我的代码中的漏洞而被抛出。我被迫承认这是行不通的。
我还进行了实验,而不是将我的对象传递给控制器的构造函数,而是在控制器已初始化的情况下在控制器上设置对象。[[after但是,这不能很好地工作,因为我需要在控制器的initialize()
方法中使用该对象,该方法称为before
objectInitialized()
)的位置进行定位;但是随后我将不得不将此方法添加到需要此功能的每个控制器中,并且我必须记住在某个时候调用所有这些方法。另外,我希望该对象成为控制器类中的final
字段;显然,如果需要在外部进行设置,它不可能是最终的。[最后,我还考虑了以下选项:对于需要包含在主FXML文件中的每个FXML文件,而不是将其包含在FMXL中,我都可以从Java控制器执行此操作。这样,我可以创建自己的FXMLLoader
,在其上设置自己的控制器实例,从而解决问题。但是,如果可能的话,我更愿意将所有UI代码保留在FXML文件中。摘要
<fx:include>
时将参数传递给控制器的构造函数的方法。我意识到这是一个漫长的问题,而且有些复杂,因此,我非常感谢您可以提供的任何帮助。另外,如果我需要澄清任何内容或发布其他代码,请在评论中让我知道。
谢谢大家的帮助!-雅各布
我正在学习JavaFX,遇到一个涉及实例化控制器的问题,我似乎无法解决。本质上,我想知道是否可以执行以下操作之一:...
<fx:include>
,而是将任何需要直接/手动从Java代码中获取参数的控制器包括在内,将变得更加容易,灵活且更具前瞻性。为什么?