如何将参数传递给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将是新窗口。问题是,我找不到一种方法来告诉控制器在哪里寻找客户的信息(通过将id作为参数传递)。

有任何想法吗?

最佳答案

推荐方法

该答案列举了将参数传递给FXML控制器的不同机制。

对于小型应用程序,我强烈建议将参数直接从调用者传递到控制器-它简单,直接并且不需要额外的框架。

对于更大,更复杂的应用程序,值得研究是否要在应用程序中使用Dependency InjectionEvent 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(
      (Pane) loader.load()
    )
  );

  CustomerDialogController controller =
    loader.<CustomerDialogController>getController();
  controller.initData(customer);

  stage.show();

  return stage;
}

...

class CustomerDialogController {
  @FXML private Label customerName;
  void initialize() {}
  void initData(Customer customer) {
    customerName.setText(customer.getName());
  }
}


如示例代码(即new FXMLLoader(location))所示,构造了一个新的FXMLLoader。该位置是一个URL,您可以通过以下方式从FXML资源生成这样的URL:

new FXMLLoader(getClass().getResource("sample.fxml"));


注意不要在FXMLLoader上使用静态加载函数,否则您将无法从加载程序实例中获取控制器。

FXMLLoader实例本身对域对象一无所知。您没有直接将应用程序特定的域对象传递到FXMLLoader构造函数中,而是:


在指定位置基于fxml标记构造FXMLLoader
从FXMLLoader实例获取控制器。
在检索到的控制器上调用方法,以为控制器提供对域对象的引用。


该博客(由另一位作者撰写)提供了一个替代的,但类似的example

在FXMLLoader上设置控制器

CustomerDialogController dialogController =
    new CustomerDialogController(param1, param2);

FXMLLoader loader = new FXMLLoader(
    getClass().getResource(
        "customerDialog.fxml"
    )
);
loader.setController(dialogController);

Pane mainPane = (Pane) loader.load();


您可以用代码构造一个新的控制器,将您想要的任何参数从调用者传递到控制器构造函数中。构造控制器后,可以在调用load()实例方法之前在FXMLLoader实例上对其进行设置。

要在装载程序(在JavaFX 2.x中)上设置控制器,您也不能在fxml文件中定义fx:controller属性。

由于FXML中fx:controller定义的限制,我个人更喜欢从FXMLLoader获取控制器,而不是将控制器设置为FXMLLoader。

让控制器从外部静态方法检索参数

这种方法以Sergey对Javafx 2.0 How-to Application.getParameters() in a Controller.java file的回答为例。

使用依赖注入

通过允许您在FXMLLoader上设置自定义控制器工厂,FXMLLoader支持诸如Guice,Spring或Java EE CDI的依赖项注入系统。这提供了一个回调,您可以使用该回调创建具有由相应依赖项注入系统注入的依赖值的控制器实例。

回答中提供了JavaFX应用程序和Spring控制器依赖注入的示例:


Adding Spring Dependency Injection in JavaFX (JPA Repo, Service)


afterburner.fx framework以使用它的示例air-hacks application为例说明了一种非常不错的干净依赖注入方法。 afterburner.fx依靠JEE6 javax.inject进行依赖项注入。

使用事件总线

最初的FXML规范创建者和实现者Greg Brown通常建议考虑使用事件总线(例如Guava EventBus)在FXML实例化控制器和其他应用程序逻辑之间进行通信。


EventBus是具有注释的简单但功能强大的发布/订阅API,它使POJO可以在JVM中的任何位置相互通信,而不必互相引用。


后续问答


在第一种方法上,为什么要返回Stage?该方法也可以是无效的,因为您已经给了命令show();。在返回阶段之前;您如何通过返回舞台来计划使用情况


这是一个解决问题的功能。从showCustomerDialog函数返回一个阶段,以便以后可能希望做某事的外部类可以存储对该阶段的引用,例如,根据在主窗口中单击按钮隐藏该阶段。另一种面向对象的解决方案可以将功能和阶段引用封装在CustomerDialog对象中,或者具有CustomerDialog扩展阶段。一个自定义对话框的面向对象的界面的完整示例,该示例对话框封装了FXML,控制器和模型数据,超出了此答案的范围,但对于那些愿意创建一个的人来说,可能是一个有价值的博客文章。



由StackOverflow用户提供的名为@dzim的其他信息

Spring Boot依赖注入示例

关于如何做的问题“ Spring Boot Way”,有一个关于JavaFX 2的讨论,我在所附的永久链接中对此进行了解答。
该方法仍然有效并且已在2016年3月的Spring Boot v1.3.3。上进行了测试。
https://stackoverflow.com/a/36310391/1281217



有时,您可能希望将结果传回给呼叫者,在这种情况下,您可以检查出相关问题的答案:


JavaFX FXML Parameter passing from Controller A to B and back

关于javafx - 传递参数JavaFX FXML,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60905760/

10-10 04:06