【问题标题】:JavaFx Progress Indicator freezes when I run another thread当我运行另一个线程时,JavaFx 进度指示器冻结
【发布时间】:2014-03-08 20:21:26
【问题描述】:

所以我一直在尝试实现一个进度指示器,但没有成功。尽管阅读了一些有关 Platform.RunLater 和 Tasks 的信息,但我不确定我是否非常了解使用 JavaFx 管理线程。所以这是我的用例。

我的程序允许用户连接到数据库并查看数据库中的一些模式和其他对象。有时连接到一个大型数据库并提取其所有表和信息需要一段时间,所以我想显示一个进度指示器。我根本不想更新进度我只想在进程运行以从数据库中提取所有内容时使进度指示器的值为 -1 可见。理想情况下,我将从不可见的 FXML 文件加载进度指示器。当我开始从数据库中提取信息的过程时,我想让它可见。

当我试图让我的进度可见时,它从未出现过,所以我决定开始让它可见并使其不可见,只是为了看看会发生什么。当我打开程序时,进度指示器很好地旋转,但是当我尝试连接到数据库时,它停止旋转并冻结。我认为这就是当我尝试使其可见时会发生的情况,这就是它从未出现的原因。

以下是我当前的代码,如果有任何详细的解释帮助,我将不胜感激,以便我了解发生了什么。谢谢

来自完成大部分工作的方法。

                //make progress indicator visible
                pi.setVisible(true);

                // separate non-FX thread
                ExtractorThread t = new ExtractorThread();
                t.setCp(cp);
                t.start();

                //Wait until the thread is done
                try{
                    t.join();
                }
                catch(Exception e){
                    e.printStackTrace();
                }

                //Retrieve the dbextractor from the thread
                DbExtractor dbe = t.getDbe();
                //move on to the next page in the application
                this.caster.goToDataSource(c, cp, dbe);

执行工作的 ExtractorThread。

private class ExtractorThread extends Thread{
    private ConnectionProperties cp;
    private DbExtractor dbe;

    public void run() {
        dbe = new DbExtractor(cp);
        try {
            dbe.extract();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   

    }

    public DbExtractor getDbe() {
        return dbe;
    }

    public void setCp(ConnectionProperties cp) {
        this.cp = cp;
    }
}

如果我应该使用 Platform.RunLater,我不确定在哪里使用它或为什么使用它。任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: java multithreading javafx-2


    【解决方案1】:

    使用 javafx.concurrent API。扩展任务而不是线程:

    private class ExtractorThread extends Task<DbExtractor>{
        private ConnectionProperties cp;
    
        public DbExtractor call() throws Exception {
            dbe = new DbExtractor(cp);
            dbe.extract();
            return dbe;   
    
        }
    
    
        public void setCp(ConnectionProperties cp) {
            this.cp = cp;
        }
    }
    

    然后做:

            //make progress indicator visible
            pi.setVisible(true);
    
            // separate non-FX thread
            final ExtractorThread t = new ExtractorThread();
            t.setCp(cp);
            t.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                public void handle(WorkerStateEvent event) {
                   DbExtractor dbExtractor = t.getValue();
                   this.caster.goToDataSource(c, cp, dbe);
                }
            });
            t.setOnFailed(...); // similarly, to handle exceptions
            new Thread(t).start();
    

    【讨论】:

    • 你我的朋友是我的英雄,这正是我需要的方式!
    【解决方案2】:

    我不会编写 JavaFX 代码,所以我不能给你章节,但是这一行:

    t.join();
    

    将阻塞调用代码,直到后台线程结束。不要这样做。而是使用某种类型的侦听器在后台线程完成时获得通知。如果这是 Swing,我会使用添加到 SwingWorker 的 PropertyChangeListener 在后台线程完成时通知我。我认为您仍然可以使用 PropertyChangeListener 来使用 JavaFX 做类似的事情,但我不能告诉您这是否代表规范的解决方案。

    另外,不要扩展 Thread 而是实现 Runnable。这不会解决您的问题,但这是基本的 Java 常识。

    【讨论】:

    • 谢谢,我过去没有真正处理过很多多线程,所以这很有帮助
    • @decal:如果这是 Swing,我会使用 PropertyChangeListener 在后台线程完成时通知我。我认为你仍然可以使用 JavaFX 做到这一点,但我不能告诉你一个规范的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-11-22
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2017-06-16
    相关资源
    最近更新 更多