2011-10-02 181 views
2

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

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

  • 在循环
  • 在每个循环迭代Thread.sleep(1000L)的每次迭代Thread.yield,在一个try/catch
  • 把一切在循环中SwingUtilities.invokeLater(Runnable)
  • 只把CPU密集型算法在一个SwingUtilities.invokeLater(Runnable)

编辑:为了进一步支持我的假设的CPU吃算法(听起来像一个孩子的故事...),当我将JProgressBar设置为不确定时,只在算法完成后才开始移动

有没有人有任何建议?

谢谢!

回答

5

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

如果你无法理解类是如何工作的,考虑:

  • SwingWorker是一个通用类,它有两个参数:T,并且V
  • doInBackground方法返回T,并在单独执行线。
  • 由于Swing只能在事件派发线程中操作,因此您不得在doInBackground中操作Swing。
  • process方法将List<V>作为参数,并在事件调度线程上异步调用。
  • publish方法需要V...参数并发送它们以便在process方法中处理。

结论:

  • T是如果任何计算的结果的类型。
  • V是操纵用户界面所需要的数据的类型。
  • 你的算法应该在doInBackground完全运行。
  • 用户界面应该在process方法中操作。
  • 您的算法应该使用publish将数据发送到process方法。
+0

谢谢,我会研究这个! – wchargin

+0

虽然我仍然对“SwingWorker”的工作原理感到困惑。我有一个'SwingWorker ,Void>'带有'ArrayList doInBackground()'和一个'void process(List chunks)'。什么是“列表”的说法?何时调用“进程”?我似乎无法理解您从我提供的链接(文档)或维基百科。你能再解释一下吗?谢谢! – wchargin

+0

也请记住,这不是一个大的任务,这是一个小百的任务(约1/4秒每个)。 – wchargin

2

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

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

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

+2

你不想直接从另一个线程更新你的UI。摆动框架设计为单线程。你想要什么用的SwingWorker类生成一个后台线程你,但可以让你发布更新回到UI线程从中你可以安全地更新进度条。在线阅读ORACLE Java教程,或者在Java中使用多线程编程的任何其他资源。 –

+1

给你正确的解决方案,使用SwingWorker。 –

+1

@HovercraftFullOfEels:是的,我会这样做;然而,请不要低估我的回答 - 我在Matheus发布了他的15秒之前发布了他的回复(可以通过在“回答...之前”文本上盘旋)来判断。 – wchargin

相关问题