在for循环中更新ProgressBar值

时间:2015-09-24 08:46:05

标签: java javafx javafx-2 javafx-8

我尝试更新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

2 个答案:

答案 0 :(得分:3)

通过手动计算和设置栏的progressProperty来重新发明轮子的另一种方法是使用任务:它有一个progressProperty,它自动计算相对数量并保证在FX应用程序线程上更新,例如将任何与场景相关的属性绑定到。

是安全的

类似的东西:

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 :(得分:1)

<强>背景

    当你在其他线程上时,会调用
  1. Platform.runLater()来执行JavaFX Application thread上的某些操作。当你已经在JavaFX应用程序线程中将所有这些项目添加到队列中时,你每100ms运行一次,因为线程已经忙于运行循环并且正在睡觉:)

    因此,在线程可以自由执行它们之后,即在完成循环之后,它会在队列中运行所有内容。

  2. 还有另一个问题,ProgressBarprogressproperty,其值可以介于0和1之间,其中0代表0%,1代表100%。如果要更新进度条,则需要使用介于0.1到1.0之间的值设置进度。

  3. 如何修复

    你应该在按钮的动作上启动一个新线程并让它处理循环。您可以在此线程中使用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()更新ProgressBar的进度,如@kleopatra在其解决方案中所述。