如何将参数传递给javafx中的辅助窗口?有没有办法与相应的控制器通信?
例如:用户从 TableView
中选择一个客户,并打开一个新窗口,显示客户的信息 .
Stage newStage = new Stage();
try
{
AnchorPane page = (AnchorPane) FXMLLoader.load(HectorGestion.class.getResource(fxmlResource));
Scene scene = new Scene(page);
newStage.setScene(scene);
newStage.setTitle(windowTitle);
newStage.setResizable(isResizable);
if(showRightAway)
{
newStage.show();
}
}
newStage
将成为新窗口 . 问题是,我可以__31605_的信息(通过传递id作为参数) .
有任何想法吗?
8 回答
以下是使用Guice注入的控制器的示例 .
这是加载器的具体实现:
请注意,此示例将视图加载到BoarderPane的中心,该BoarderPane是舞台中场景的根 . 这与示例(我的具体用例的实现细节)无关,但决定将其保留,因为有些人可能觉得它很有用 .
This WORKS ..
Remember first time you print the passing value you will get null, You can use it after your windows loaded , same for everything you want to code for any other component.
Recommended Approach
这个答案列举了将参数传递给FXML控制器的不同机制 .
对于小型应用程序,我强烈建议将参数直接从调用者传递给控制器 - 它简单,直接,不需要额外的框架 .
对于更大,更复杂的应用程序,如果要在应用程序中使用Dependency Injection或Event Bus机制,则值得研究 .
Passing Parameters Directly From the Caller to the Controller
通过从FXML加载程序实例检索控制器并调用控制器上的方法以使用所需的数据值对其进行初始化,将自定义数据传递给FXML控制器 .
类似下面的代码:
构造一个新的FXMLLoader,如示例代码所示,即
new FXMLLoader(location)
. 该位置是一个URL,您可以通过以下方式从FXML资源生成此类URL:注意不要在FXMLLoader上使用静态加载功能,否则您将无法从加载器实例中获取控制器 .
FXMLLoader实例本身对域对象一无所知 . 您不直接将特定于应用程序的域对象传递给FXMLLoader构造函数,而是:
根据指定位置的fxml标记构造FXMLLoader
从FXMLLoader实例获取控制器 .
在检索到的控制器上调用方法,以向控制器提供对域对象的引用 .
这个博客(由另一位作家提供)提供了一个替代的,但类似的,example .
Setting a Controller on the FXMLLoader
您可以在代码中构造一个新控制器,将您想要的任何参数从调用者传递到控制器构造函数中 . 构建控制器后,可以在调用
load()
实例方法之前在FXMLLoader实例上进行设置 .要在加载器上设置控制器(在JavaFX 2.x中),您也不能在fxml文件中定义
fx:controller
属性 .由于FXML中
fx:controller
定义的限制,我个人更喜欢从FXMLLoader获取控制器,而不是将控制器设置为FXMLLoader .Having the Controller Retrieve Parameters from an External Static Method
这种方法的例子是谢尔盖对Javafx 2.0 How-to Application.getParameters() in a Controller.java file的回答 .
Use Dependency Injection
FXMLLoader支持依赖注入系统,如Guice,Spring或Java EE CDI,允许您在FXMLLoader上设置自定义控制器工厂 . 这提供了一个回调,您可以使用该回调来创建具有相应依赖注入系统注入的依赖值的控制器实例 . 有一个集成FXML with the Spring dependency injection system的样本(不幸的是链接已经死了,内容已经消失,如果有人知道类似的例子,请编辑这个问题以引用它),虽然它比使用新的自定义控制器有点笨拙工厂功能在JavaFX 2.2中提供 .
一个非常好的,干净的依赖注入方法由afterburner.fx framework以及使用它的样本air-hacks application举例说明 . afterburner.fx依赖于JEE6 javax.inject来执行依赖注入 .
Use an Event Bus
最初的FXML规范创建者和实现者Greg Brown经常建议考虑使用event bus来实现FXML实例化控制器和其他应用程序逻辑之间的通信 .
Follow-up Q&A
它是解决问题的功能性解决方案 . 从
showCustomerDialog
函数返回一个阶段,以便对可能希望执行某些操作的外部类存储对它的引用,例如在稍后的时间基于主窗口中的按钮单击隐藏阶段 . 另一种面向对象的解决方案可以将功能和阶段引用封装在CustomerDialog对象中,或者具有CustomerDialog扩展阶段 . 自定义对话框封装的面向对象接口的完整示例FXML,控制器和模型数据超出了这个答案的范围,但可能会为任何倾向于创建它的人制作一篇有 Value 的博客文章 .Additional information supplied by StackOverflow user named @dzim
Spring Boot Dependency Injection的示例
关于如何做到的问题"The Spring Boot Way",有一个关于JavaFX 2的讨论,我在附加的永久链接中对此进行了回答 . 该方法仍然有效,并于2016年3月在Spring Boot v1.3.3上进行了测试.RELEASE:https://stackoverflow.com/a/36310391/1281217
有时,您可能希望将结果传递回调用者,在这种情况下,您可以查看相关问题的答案:
在这个例子中,我们将使用5个文件:
Main.java - 仅用于启动应用程序并调用第一个控制器 .
Controller1.java - 第一个FXML布局的控制器 .
Controller2.java - 第二个FXML布局的控制器 .
Layout1.fxml - 第一个场景的FXML布局 .
Layout2.fxml - 第二个场景的FXML布局 .
所有文件都在本文的底部完整列出 .
The Goal: 演示从
Controller1
到Controller2
的传递值,反之亦然 .The Program Flow:
第一个场景包含
TextField
,Button
和Label
. 单击Button
时,将加载并显示第二个窗口,包括在TextField
中输入的文本 .在第二个场景中,还有一个
TextField
,一个Button
和一个Label
.Label
将显示在第一个场景中TextField
中输入的文本 .在第二个场景
TextField
中输入文本并单击其Button
后,第一个场景的Label
将更新以显示输入的文本 .这是一个非常简单的演示,肯定会有一些改进,但应该使概念非常清晰 .
代码本身也会对正在发生的事情以及如何进行评论 .
Main.java:
Controller1.java:
Controller2.java:
Layout1.fxml:
Layout2.fxml:
以下是通过命名空间将参数传递给fxml文档的示例 .
为名称空间变量
labelText
定义值External Text
:您必须创建一个Context类 .
您必须在初始化时使用设置控制器的实例
你可以在整个应用程序中使用它
现在您可以将参数传递给整个应用程序的任何控制器 .
您可以决定使用公共可观察列表来存储公共数据,或者只创建一个公共setter方法来存储数据并从相应的控制器中检索
javafx.scene.Node类有一对方法setUserData(Object)和Object getUserData()
您可以使用它将您的信息添加到节点 .
所以,你可以调用page.setUserData(info);
如果设置了信息,控制器可以检查 . 此外,如果需要,您可以使用ObjectProperty进行后向数据传输 .
在此处观察文档:http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html在短语"In the first version, the handleButtonAction() is tagged with @FXML to allow markup defined in the controller's document to invoke it. In the second example, the button field is annotated to allow the loader to set its value. The initialize() method is similarly annotated."之前
因此,您需要将控制器与节点相关联,并将用户数据设置为节点 .