在继续之前等待Swing完成更新JProgressBar

时间:2011-10-02 00:14:14

标签: java multithreading performance swing

我有一个JFrame,其CardLayout设置为其布局管理器。这里有两个JPanel子类。一个是面板WordsLoadingPanel,它显示文本“正在加载单词...”并且有一个JProgressBar。另一个必须实际加载单词。这需要一段时间(对于100个单词大约10-14秒;这是一个非常有选择性的算法),所以我想向用户保证该程序仍在工作。我在面板中使用加载算法激活了firePropertyChange(String, int, int)的属性更改,并且WordsLoadingPanel正在捕获更改 - 我知道这是因为我为此事件添加了一个侦听器来执行{{1它有效。但是,当我将println更改为实际更改println的值时,它不会执行任何操作。我知道我正在改变正确的值,因为如果我在算法开始之前设置了值,它就可以工作,它可以在循环的最后一次迭代中工作。我猜这是因为我的算法正在消耗计算能力,不会让JProgressBar更新。

所以,我的问题是:如何让我的算法等待Swing(这是AWT调度线程?)在继续之前完成更新进度条?我试过了:

    在循环的每次迭代中
  • JProgressBar
  • 循环的每次迭代中的
  • Thread.yield,在try / catch
  • 将所有内容放入Thread.sleep(1000L)
  • 的循环中
  • 只将CPU密集型算法放入SwingUtilities.invokeLater(Runnable)

编辑:为了进一步支持我关于CPU吃饭算法的假设(听起来像孩子的故事......),当我将SwingUtilities.invokeLater(Runnable)设置为不确定时,它只会在之后开始移动算法完成。

有人有任何建议吗?

谢谢!

2 个答案:

答案 0 :(得分:5)

要在后台执行昂贵的操作,请考虑使用SwingWorker类。该文档包含有关如何使用它来执行与单独线程中的用户界面交互的任务的示例,包括JProgressBar中的进度显示。

如果您无法理解课程的运作方式,请考虑:

  • SwingWorker是一个通用类,它带有两个参数:TV
  • doInBackground方法返回T并在单独的线程中执行。
  • 由于Swing只能在Event Dispatch Thread中操作,因此您可能无法在doInBackground中操纵Swing。
  • process方法将List<V>作为参数,并在事件调度线程上异步调用。
  • publish方法接受V...个参数并将其发送给process方法进行处理。

总结:

  • T是计算结果的类型,如果有的话。
  • V是操作用户界面所需的数据类型。
  • 您的算法应完全在doInBackground
  • 中运行
  • 应使用process方法操作用户界面。
  • 您的算法应使用publish将数据发送到process方法。

答案 1 :(得分:2)

好的,我已经解决了。对于任何可能遇到类似问题的人,我的解决方案是将开始算法的方法从同步执行到异步(使用new Thread(Runnable).start)。所以,我的代码现在是

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        new Thread(new Runnable () {
            public void run () {
                window.keyboardTrainingPanel.initialize();                                  
            }
        }).start();
    }
});

我希望这可以帮助别人!但是,如果有更好的方法,请随时通知我。