使用MVC
这个回答的大部分内容都集中在直接调用来将参数从调用类传递到控制器。
如果您想要解耦调用方和控制器,并使用更通用的体系结构,涉及到一个具有可设置和可监听属性的模型类以实现控制器间通信,请参阅以下基本概述:
推荐方法
此答案列举了将参数传递给FXML控制器的不同机制。
对于小型应用程序,我强烈建议直接从调用方传递参数到控制器 - 这是简单、直接的,不需要额外的框架。
对于更大、更复杂的应用程序,值得研究是否要在应用程序中使用Dependency Injection或Event Bus机制。
直接从调用方传递参数到控制器
通过从FXML加载器实例中检索控制器并调用控制器上的方法将自定义数据传递给FXML控制器,以使用所需的数据值对其进行初始化。
类似以下代码:
public Stage showCustomerDialog(Customer customer) {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(
new Scene(loader.load())
);
CustomerDialogController controller = loader.getController();
controller.initData(customer);
stage.show();
return stage;
}
...
class CustomerDialogController {
@FXML private Label customerName;
void initialize() {}
void initData(Customer customer) {
customerName.setText(customer.getName());
}
}
示例代码中构造了一个新的FXMLLoader,即new FXMLLoader(location)
。location是一个URL,您可以通过以下方式从FXML资源生成这样的URL:
new FXMLLoader(getClass().getResource("sample.fxml"))
注意不要在FXMLLoader上使用静态负载函数,否则您将无法从加载程序实例中获取控制器。
FXMLLoader实例本身永远不知道任何关于域对象的信息。 您不会直接将应用程序特定的域对象传递到FXMLLoader构造函数中,而是:
- 基于指定位置的fxml标记构建FXMLLoader
- 从FXMLLoader实例中获取控制器。
- 调用检索到的控制器上的方法,向控制器提供对域对象的引用。
这篇博客(由另一位作者撰写)提供了一个替代但类似的示例。
在FXMLLoader上设置控制器
CustomerDialogController dialogController =
new CustomerDialogController(param1, param2);
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
loader.setController(dialogController);
Pane mainPane = loader.load();
你可以在代码中构建一个新的控制器,将任何参数从调用者传递到控制器构造函数中。一旦你构建了一个控制器,你可以在调用
load()
实例方法之前,在FXMLLoader实例上设置它。
在FXML中由于
fx:controller
定义的限制,我个人更喜欢从FXMLLoader获取控制器而不是将控制器设置到FXMLLoader中。
让控制器从外部静态方法中检索参数
Sergey对
Javafx 2.0 How-to Application.getParameters() in a Controller.java file的回答展示了这种方法。
使用依赖注入
FXMLLoader支持依赖注入系统,如Guice、Spring或Java EE CDI,通过允许你在FXMLLoader上设置自定义控制器工厂。这提供了一个回调,你可以使用它来创建具有相关依赖值注入的控制器实例。
以下是关于JavaFX应用程序和控制器依赖注入的示例,使用Spring进行注入。答案提供在以下链接中:
一个非常好的、干净的依赖注入方法是afterburner.fx框架,它有一个使用该框架的样例air-hacks应用程序。afterburner.fx依靠JEE6 javax.inject执行依赖注入。
使用事件总线
FXML规范的原始创建者和实现者Greg Brown经常建议考虑使用事件总线(例如Guava EventBus)来在FXML实例化的控制器和其他应用程序逻辑之间进行通信。
事件总线是一个简单但功能强大的发布/订阅API,具有注解功能,允许普通Java对象在JVM中相互通信,而无需彼此引用。
跟进问答
对于第一个方法,为什么要返回Stage?该方法也可以是void类型,因为您已经在return stage;之前给出了show()命令。你如何计划通过返回阶段来使用它?
这是将重要参考内容存储在外部类中的函数式解决方案。从showCustomerDialog函数返回一个Stage,以便后续可能需要执行其他操作的外部类(例如基于主窗口中的按钮单击隐藏stage)。另一种面向对象的解决方案可以将该功能和Stage引用封装在CustomerDialog对象中,或者使CustomerDialog扩展Stage。针对自定义对话框的面向对象接口、封装FXML、控制器和模型数据的完整示例超出了本答案的范围,但对于任何想要创建此类示例的人来说,这可能是一篇有价值的博客文章。
由StackOverflow用户@dzim提供的额外信息
Spring Boot依赖注入示例
如何以“Spring Boot方式”进行依赖注入的问题,在附加的永久链接中有关于JavaFX 2的讨论,我在那里回答了这个问题。
这种方法在2016年3月已经测试过,并且在Spring Boot v1.3.3.RELEASE上仍然有效:
https://dev59.com/XpPfa4cB1Zd3GeqPDnrL#36310391
有时候,您可能希望将结果传回给调用者,这时您可以查看相关问题的答案: