在for循环中更新ProgressBar值



我试图在for循环中更新ProgressBar值。它的进度应该每100毫秒更新一次,但不幸的是它没有工作!下面是代码:

pb = new ProgressBar(0);
Button btn = new Button("Start!");
btn.setOnAction(new EventHandler<ActionEvent>(){
    @Override
    public void handle(ActionEvent event) {
        for(int i = 0; i <=100; i++){
            position = i;
            Platform.runLater(new Runnable(){
                @Override
                public void run() {
                    pb.setProgress(position);
                    System.out.println("Index: "+position);
                }
            });
            try{
                Thread.sleep(100);
            }catch(Exception e){ System.err.println(e); }
        }
    }
});

问题1:我期望上面的代码每100毫秒更新一次进度条,但它没有工作。为什么?

问题2:我在循环中调用System.out.println("Index: "+position);。我假设输出应该是1..2..3..4...,但是我错了。输出如下所示:

Index: 100
Index: 100
Index: 100
Index: 100
Index: 100
Index: 100
Index: 100

通过手动计算和设置工具条的progressProperty来重新发明轮子的替代方法是使用Task:它有一个progressProperty,可以自动计算相对数量并保证在FX-application线程上更新,这样可以安全地绑定任何与场景相关的属性。

类似:

Task<Void> task = new Task<Void>() {
    @Override
    protected Void call() throws Exception {
        double max = 137;
        for (int i = 0; i <= max; i++) {
            updateProgress(i, max);
            Thread.sleep(100);
        }
        return null;
    }
};
button.setOnAction(e -> {
    // a task is not reusable, disable
    button.setDisable(true);
    // bind "late" to not get an initial indeterminate PB
    bar.progressProperty().bind(task.progressProperty());
    new Thread(task).start();
});

显然,这是最简单的代码片段——参见Task中的例子,可以很好地取消/中断线程。

背景

    当您在其他线程上时,调用
  1. Platform.runLater()来执行JavaFX Application thread上的某些操作。当您已经在JavaFX应用程序线程上向队列中添加所有这些项目时,您每100毫秒运行一次它,因为线程已经忙于运行循环和睡眠:)

    所以它在线程空闲后运行队列中的所有内容,即在完成循环后。

  2. 还有一个问题,ProgressBar有一个progressproperty,它的值可以在0到1之间,其中0代表0%,1代表100%。如果你想更新进度条,你会想把进度设置为0.1到1.0之间的值。

如何修复

你应该在按钮的动作上启动一个新的线程,并让它处理循环。您可以在这个线程中使用Platform.runLater,而不会阻塞JavaFX应用程序线程。

我将运行如下代码:

btn.setOnAction(event -> {
    new Thread(() -> {
         for(int i = 0; i <=100; i++){
            final int position = i;
            Platform.runLater(() -> {
                pb.setProgress(position/100.0);
                System.out.println("Index: " + position);
            });
            try{
                Thread.sleep(100);
            }catch(Exception e){ System.err.println(e); }
         }
    }).start();
});

注意:这个答案更多地强调OP哪里出错了以及他如何纠正它。如果你在JavaFX上,你会想要使用更好的方法,即使用Task和它的updateProgress()来更新@kleopatra在她的解决方案中所述的ProgressBar的进度。

最新更新