我的 UI 中有一个 javafx Progressbar,然后我有一个 for 循环。 在 for 循环的每次迭代中,都会发生这种情况:
progressVal += 5.0;
progress.setProgress(progressVal);
在整个循环之后,会发生这种情况:
progress.setProgress(100);
我现在已经认识到 UI 控件仅在该方法完成后才刷新,因此进度条直到结束才会更新,并且会立即设置为 100。
那么是否有可能以某种方式强制更新 UI,即使该方法没有完全完成?或者我还能怎么做?
最佳答案
如果您在循环中执行的操作需要很长时间并且不应该在 JavaFX 应用程序线程上执行(它可能会执行或者您可能不会有这个问题),那么您应该在一个Task ,在不同的线程上,随着循环的进行更新任务的进度,并将进度条的值绑定(bind)到任务的进度。
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ProgressFeedback extends Application {
private static final double EPSILON = 0.0000005;
@Override
public void start(Stage stage) throws Exception {
final Task<Void> task = new Task<Void>() {
final int N_ITERATIONS = 100;
@Override
protected Void call() throws Exception {
for (int i = 0; i < N_ITERATIONS; i++) {
updateProgress(i + 1, N_ITERATIONS);
// sleep is used to simulate doing some work which takes some time....
Thread.sleep(10);
}
return null;
}
};
final ProgressBar progress = new ProgressBar();
progress.progressProperty().bind(
task.progressProperty()
);
// color the bar green when the work is complete.
progress.progressProperty().addListener(observable -> {
if (progress.getProgress() >= 1 - EPSILON) {
progress.setStyle("-fx-accent: forestgreen;");
}
});
// layout the app
final StackPane layout = new StackPane(progress);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
final Thread thread = new Thread(task, "task-thread");
thread.setDaemon(true);
thread.start();
}
public static void main(String[] args) {
launch(args);
}
}
what if the task makes call to a method that does only a single job , and do not want it to be called again and again?
然后移除循环并随着作业的进行通过作业内的多次调用来调用 updateProgress。该循环仅出于演示目的出现在该示例中,因为这是原始问题专门询问的内容。
例如,假设您的工作有 3 个阶段:从数据库中获取数据、执行计算和累积结果。每个阶段估计分别占总时间的 30%、60% 和 10%,然后您可以在任务的 call()
主体内执行如下操作:
updateProgress(0, 1.0);
Data data = db.fetchData(query);
updateProgress(0.3, 1.0);
ProcessedData processed = calculator.process(data);
updateProgress(0.9, 1.0);
Result result = accumulator.reduce(processed);
updateProgress(1.0, 1.0);
关于JavaFX刷新方法内的进度条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24326324/