一尘不染

传递参数JavaFX FXML

javascript

如何将参数传递给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作为参数传递)。

有任何想法吗?


阅读 786

收藏
2020-09-27

共1个答案

一尘不染

推荐方法

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

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

对于更大,更复杂的应用程序,如果您想在应用程序中使用依赖注入或事件总线机制,则值得研究。

直接从调用者向控制器传递参数

通过从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)。该位置是一个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实例上对其进行设置。

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

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

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

该方法以Sergey对Controller.java文件中的Javafx 2.0 How-to Application.getParameters()的回答为例。

使用依赖注入

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

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

在JavaFX中添加Spring依赖注入(JPA存储库,服务)
afterburner.fx框架示例了一个很好的,干净的依赖项注入方法,该示例带有一个使用它的示例空破解应用程序。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

2020-09-27