Java 更新for循环中的ProgressBar值

Java 更新for循环中的ProgressBar值,java,javafx,javafx-2,javafx-8,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

我试图更新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); }
        }
    }
});

背景

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

    因此,它在线程可以自由执行队列中的所有内容后(即完成循环后)运行队列中的所有内容

  • 还有一个问题,其值可以介于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();
    });
    
    btn.setOnAction(事件->{
    新线程(()->{
    对于(int i=0;i{
    pb.设定进度(位置/100.0);
    系统输出打印项次(“索引:+位置);
    });
    试一试{
    睡眠(100);
    }catch(异常e){System.err.println(e);}
    }
    }).start();
    });
    

    注意:这个答案更强调OP哪里出了问题,以及他如何纠正。如果您使用的是JavaFX,您可能希望使用更好的方法,即使用和its更新@kleopatra在其解决方案中所述的ProgressBar进度。

    背景

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

    因此,它在线程可以自由执行队列中的所有内容后(即完成循环后)运行队列中的所有内容

  • 还有一个问题,其值可以介于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();
    });
    
    btn.setOnAction(事件->{
    新线程(()->{
    对于(int i=0;i{
    pb.设定进度(位置/100.0);
    系统输出打印项次(“索引:+位置);
    });
    试一试{
    睡眠(100);
    }catch(异常e){System.err.println(e);}
    }
    }).start();
    });
    

    注意:这个答案更强调OP哪里出了问题,以及他如何纠正。如果您使用的是JavaFX,您可能希望使用更好的方法,即使用和its更新进度条的进度,如@kleopatra在其解决方案中所述。

    通过手动计算和设置进度条的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 Task=新任务(){
    @凌驾
    受保护的Void调用()引发异常{
    双倍最大值=137;
    对于(int i=0;i{
    //任务不可重用,请禁用
    按钮。设置禁用(true);
    //绑定“late”以不获取初始不确定PB
    bar.progressProperty().bind(task.progressProperty());
    新线程(任务).start();
    });
    

    显然,这是最简单的一个片段-请参阅,以获取取消/中断线程的示例。

    通过手动计算和设置进度条的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 Task=新任务(){
    @凌驾
    受保护的Void调用()引发异常{
    双倍最大值=137;
    对于(int i=0;i{
    //任务不可重用,请禁用
    按钮。设置禁用(true);
    //绑定“late”以不获取初始不确定PB
    bar.progressProperty().bind(task.progressProperty());
    新线程(任务).start();
    });
    

    显然,这是最简单的代码片段-请参阅取消/中断线程的示例。

    您的代码存在多个问题,第一个问题是在JavaFX应用程序线程上运行循环。由于您的循环使当前线程处于休眠状态,我将在后台线程上运行它。这意味着什么?我宁愿给出一个答案而不是写评论,给我一些时间:)无关:代码标记用于…代码(与任意突出显示相比;)标记关键字或类/方法名称是边界(阅读:辩论)-就我个人而言,我很少这样做,因为它会中断阅读流程(@ItachiUchiha也是,JavaFX应用程序线程与实际代码无关;-)@kleopatra对不起,我不知道你在说什么:p你的代码有多个问题,第一个问题是在JavaFX应用程序线程上运行循环。由于你的循环使当前线程处于休眠状态,我