如何解决将数据传递给 Javafx 中的另一个控制器
我仍然是用 Java 开发我的项目的新手,你能指出我在将 String 传递给另一个控制器时做错了什么吗?下面是我的解决方案。我试图将字符串 purchaseCode
的值从我的第一个控制器 (DashboardController.java
) 传递给另一个控制器,以便在查询中使用它或只是将其设置为文本。但是当我将它调用到我的另一个控制器 (InfoSalesController.java
) 时,结果是 null。
DashboardController.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);
}
解决方法
这个问题实际上是重复的:
但是这个问题提出了一个有趣的附带问题:“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());
}
}
这里的主要区别在于 CustomerDialogController 中的 initialize()
语句为空,并且添加了单独的 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);
}
这不起作用,因为调用 initialize 语句时 purchaseTxt 为空。
但如果您执行以下操作,则purchaseTxt 不为空:
@Override
public void initialize(URL url,ResourceBundle rb) {
Platform.runLater(() -> {
purchaseTxt.setText(purchaseSales);
});
}
将 initialize()
的内容包装在 Platform.runLater()
中的作用是将初始化函数的处理延迟到未来某个未定义的点。
可能会在下一个场景脉冲处执行。 pulse 基于 JavaFX 用于处理动画和布局更改以及向应用程序代码发送事件和回调的内部计时器。
例如,Platform.runLater()
代码可以在 1/60 秒后执行,之后:
- 应用程序中针对当前脉冲的所有后续语句均已执行并且
- 控制权已移交给 JavaFX 应用程序框架,该框架执行动画、渲染和布局过程 AND
- 控制权已返回给您的应用程序代码,以便为下一个脉冲执行应用程序处理。
因此,Platform.runLater()
有效地使初始化过程成为异步调用。在执行完所有后续代码后,将执行异步逻辑。这意味着您在新控制器中设置应用程序数据的代码将在执行 initialize()
Platform.runLater()
块中的异步代码以初始化由新控制器管理的视图元素之前执行。
这两种方法都是有效的。我想您可以选择您和其他读者最清楚的一种。就我个人而言,在这种情况下我不会使用 Platform.runLater()
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。