我可以解释一下更新 GUI 线程是如何工作的吗?对我来说这一切都很困惑。 例如,我想循环更新 ProgressBar。我知道我需要将循环放入新任务中。我将 ProgressBar 的 ProgressProperty 绑定(bind)到任务的进度。
如果我用
调用任务new Thread(task).start();
结合调用函数中Task的updateProgress()方法,运行正常,进度条更新了。
问题一:为什么我在循环内直接设置进度(progressProperty 未绑定(bind))来更新 ProgressBar 时失败?如果我想将其设置在循环内部(不)可见,也会发生同样的情况。
问题2:让progressProperty绑定(bind)到Task.progressProperty。为什么我无法通过使用 Plateform.runLater(task) 调用任务来更新进度条?它不会更新 GUI 线程。
问题 3:如何设置循环内进度条的可见性?
public class PRogressBar extends Application {
ProgressBar progressBar;
@Override
public void start(Stage stage) {
/**
Task for updating the ProgressBar
*/
Task<Void> task = new Task() {
@Override
protected Object call() throws Exception {
System.out.println("Init Task");
// progressBar.setVisible(false) // Question 3
// progressBar.setProgress(0.75) // question 1
for (int i = 1; i < 5; i++) {
final int update = i;
try {
Thread.sleep(500);
System.out.println("Run later : " + update/5.0);
updateProgress(i, 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
};
/*
Initializing the GUI
*/
progressBar = new ProgressBar();
Button button = new Button("blou");
button.setOnAction((event) -> {
// Platform.runLater(task); // Question 2
Thread th = new Thread(task);
// th.setDaemon(true);
th.start();
System.out.println("Thread started");
});
StackPane layout = new StackPane();
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
HBox hbox = new HBox(progressBar, button);
layout.getChildren().add(hbox);
progressBar.setProgress(0.1);
// setVisible2(false);
// progressBar.progressProperty().bind(task.progressProperty());
stage.setScene(new Scene(layout));
stage.show();
}
最佳答案
Question one : why do I fail at updating the ProgressBar by setting directly its progress inside of the loop (progressProperty being not binded) ? Same occurs if I want to set it (non-)visible inside of the loop.
因为影响当前显示舞台的所有 UI 更改都必须在 JavaFX 应用程序线程中执行。您的任务在您自己的线程中执行,因此请确保在 JavaFX 应用程序线程中调用 setProgress 和 setVisible。您必须通过 Platform.runLater(() -> {//change UI});
updateProgress 和 updateMessage 是线程安全。也许这些方法会影响 UI,例如。 G。如果您已将 ProgressProperty 绑定(bind)到 ProgressBar。您可以以安全的方式从工作线程调用它。但updateProgress是异常(exception)而不是规则。
Question 2 : Let the progressProperty be binded to the Task.progressProperty. Why can't I update the progressBar by calling the Task with Plateform.runLater(task) ? It won't update the GUI thread.
你的意思是Platform.runLater(() -> myTask.call());
?这应该可行,因为 call 在 JavaFX 应用程序线程中执行,因此您可以更改 UI。但这不是您处理任务的方式:)
Question 3 : how do I set the visibility of the progressBar inside of the loop?
您位于 JavaFX 应用程序线程之外,因此必须使用 Platform.runLater(...)
。
顺便说一句,Brian Goetz 在他的《Java Concurrency in Practice》一书中第 9.1 章描述了为什么 GUI 是单线程的?。
关于java - 了解线程中更新 GUI 的工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25549423/