首页 > 解决方案 > 将数据传递给 Javafx 中的另一个控制器

问题描述

我仍然是用Java开发我的项目的新手,你能指出我在将字符串传递给另一个控制器时做错了什么吗?下面是我的解决方案。我试图将 String 的值purchaseCode从我的第一个控制器(DashboardController.java)传递到另一个控制器,以便在查询中使用它或者只是将其设置为文本。但是当我将它调用到我的另一个控制器(InfoSalesController.java)时,我得到了 null。

仪表板控制器.java

...
SalesController sales = getTableView().getItems().get(getIndex());
String purchaseCode = sales.getPurchaseCol();
Hyperlink link = new Hyperlink(purchaseCode);
                             
link.setOnAction(event->{
  try{
    Stage stage = new Stage();
    FXMLLoader loader = new 
    FXMLLoader(getClass().getResource("/store/sales/infoSales.fxml"));
    Parent pane = (Parent) loader.load();
    InfoSalesController is = loader.getController();
    is.setPurchaseSales(purchaseCode);
    stage.setScene(new Scene(pane));
    stage.setResizable(false);
    stage.initModality(Modality.APPLICATION_MODAL);
    stage.show();
    }catch(IOException e){
      e.printStackTrace();
    }
});
setGraphic(link);
...

InfoSalesController.java

public String getPurchaseSales() {
    return purchaseSales;
}

public void setPurchaseSales(String purchaseSales) {
    this.purchaseSales = purchaseSales;
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    purchaseTxt.setText(purchaseSales);
}

标签: javajavafx-8

解决方案


这个问题实际上是重复的:

但是这个问题提出了一个有趣的附带问题:“程序如何Platform.runLater()帮助程序工作?”,我将在这里发布一个答案作为解释。

首先,让我们看一下传递参数答案中的代码并解释它是如何工作的:

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());
  }
}

这里的关键区别在于initialize()CustomerDialogController 中的语句是空的,并且initData()添加了一个单独的函数。initialize()在加载 FXML 时,FXMLLoader 会隐式调用该语句。那时,初始化视图实际所需的其余数据(客户数据)不可用,因为它尚未传递给新控制器。该initData(Customer customer)调用在加载后显式进行,并包含客户数据作为参数,因此可用于初始化视图。

现在让我们看看您问题中的代码以及Platform.runLater它的作用。

您的调用控制器中有此代码:

FXMLLoader loader = new 
FXMLLoader(getClass().getResource("/store/sales/infoSales.fxml"));
Parent pane = (Parent) loader.load();
InfoSalesController is = loader.getController();
is.setPurchaseSales(purchaseCode);

这在您的接收控制器中:

public void setPurchaseSales(String purchaseSales) {
    this.purchaseSales = purchaseSales;
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    purchaseTxt.setText(purchaseSales);
}

这不起作用,因为在调用初始化语句时 purchaseTxt 为空。

但如果您执行以下操作,则 purchaseTxt 不为空:

@Override
public void initialize(URL url, ResourceBundle rb) {
    Platform.runLater(() -> {
        purchaseTxt.setText(purchaseSales);
    });  
}

包装initialize()in的内容Platform.runLater()是将初始化函数的处理延迟到将来某个未定义的点。

执行可能会在下一个场景脉冲发生。脉冲基于 JavaFX 用于处理动画和布局更改并将事件和回调发送到应用程序代码的内部计时器。

例如,Platform.runLater()代码可以在 1/60 秒后执行,之后:

  1. 您的应用程序中针对当前脉冲的所有后续语句都已执行并且
  2. 控制权已移交给执行动画、渲染和布局过程的 JavaFX 应用程序框架,并且
  3. 控制已返回到您的应用程序代码以执行下一个脉冲的应用程序处理。

因此,有效地Platform.runLater()使初始化过程成为异步调用。在执行完所有后续代码后,将执行异步逻辑。这意味着您在新控制器中设置应用程序数据的代码将在执行initialize() Platform.runLater()块中的异步代码以初始化由新控制器管理的视图元素之前执行。

两种方法都有效。我想你可以选择对你和其他读者来说最清楚的一个。就个人而言,我不会Platform.runLater()在这种情况下使用。


推荐阅读