当用户选择在另一个线程中启动阻止进程的菜单项时,我试图在JavaFX 8应用程序中提供反馈。在我的实际应用程序中,它是一个文件下载,但我通过示例使用最少的代码创建了一个测试用例:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.MenuButton;
import javafx.scene.control.ToolBar;
import javafx.scene.control.MenuItem;
import javafx.stage.Stage;
public class BlockingThreadTestCase extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
MenuItem menuItem = new MenuItem("Start");
MenuButton menuButton = new MenuButton();
menuButton.setText("Async Process");
menuButton.getItems().addAll(menuItem);
menuItem.setOnAction(event -> {
menuButton.setText("Running...");
Platform.runLater(() -> {
try {
// Simulate a blocking process
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
menuButton.setText(menuButton.getText() + "Done!");
});
});
final ToolBar toolbar = new ToolBar(menuButton);
final Scene scene = new Scene(toolbar);
primaryStage.setScene(scene);
primaryStage.setWidth(150);
primaryStage.show();
}
}
以下是它应该如何工作:当您选择“开始”菜单项时,主菜单文本应立即更改为“正在运行...”,然后它应附加“完成!”在模拟我的文件下载的5秒睡眠之后。
实际发生的是两个文本更新在阻止过程完成后触发,即使我正在使用Platform.runLater()
。我做错了什么?
答案 0 :(得分:8)
最简单的方法是使用Task
。仅当您需要从其他线程更新UI时才需要Platform.runLater
,因此在您的情况下不需要。如果您希望在后台任务运行时跟踪后台任务的进度,您可以在任务中使用updateMessage
和updateProgress
方法将消息安全地传递到UI线程,而不必担心通过EDT进行调度。您可以在https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm找到更多相关信息。
请参阅下面的最小工作示例。
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ToolBar;
import javafx.stage.Stage;
public class BlockingThreadTestCase extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
MenuItem menuItem = new MenuItem("Start");
MenuButton menuButton = new MenuButton();
menuButton.setText("Async Process");
menuButton.getItems().addAll(menuItem);
menuItem.setOnAction(event -> {
menuButton.setText("Running...");
Task task = new Task<Void>() {
@Override
public Void call() {
//SIMULATE A FILE DOWNLOAD
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
};
task.setOnSucceeded(taskFinishEvent -> menuButton.setText(menuButton.getText() + "Done!"));
new Thread(task).start();
});
final ToolBar toolbar = new ToolBar(menuButton);
final Scene scene = new Scene(toolbar);
primaryStage.setScene(scene);
primaryStage.setWidth(150);
primaryStage.show();
}
}