2

我在 JFrame 中构建了一个 UI。其中一个按钮启动了一个长时间运行的调用(仍在同一个 java 进程中),并且在它执行期间,UI 被冻结。

我想,为了清楚地表明事情仍在运行,我可以显示一个进度条,也许在一个弹出窗口中,以便用户可以随时了解程序正在做什么。

所以我正在创建一个新的 JDialog,向它添加一个 JProgressBar,并在事情发生时对其进行更新。问题是该对话框的内容没有得到更新。我对其标题所做的更改会立即显示,我输出到控制台的任何内容都会立即显示,但 UI 本身没有任何内容。

有没有我可以发出强制重绘的命令?

这是本节的核心:

  killWindow = new JDialog();
  killWindow.setUndecorated(true);
  killWindow.setTitle("stopping tests - 0 of " + numActive);
  killProgress = new JProgressBar(0, numActive);
  killWindow.add(killProgress);
  killProgress.setStringPainted(true);
  killWindow.pack();
  killWindow.setLocationRelativeTo(frame);
  killWindow.setVisible(true);

然后,随着我们的进步......:

  killProgress.setValue(++killedTests);                    // not seen!
  killProgress.setString("Killing test on " + nickname()); // not seen!
  log("Killed another test, " + killedTests + " so far");  // visible in real time
  killWindow.setTitle("stopping tests - " + killedTests +
                      " of " + killProgress.getMaximum()); // visible in real time

我错过了什么?我尝试在 SO 上搜索和搜索,并没有真正看到任何明显的东西?

4

2 回答 2

4

您必须在另一个线程中执行长时间运行的任务。

有一个名为“AWT Event Dispatch Thread”的线程负责 UI 组件的更新。如果它正忙于执行您长时间运行的任务,它将不会更新 UI(也不会刷新您的对话框)。

您可以考虑使用SwingUtilitiesSwingWorker

从 SwingWorker文档这里是一个示例

final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
   @Override
   public String doInBackground() {
       return findTheMeaningOfLife();
   }

   @Override
   protected void done() {
       try { 
           label.setText(get());
       } catch (Exception ignore) {
       }
   }
}

(new MeaningOfLifeFinder()).execute();

通过在不同的线程中运行长任务,您允许 AWT 事件调度线程显示响应式 UI。

您可以查看“ Java 教程中的课程”以更好地理解这些概念。

于 2009-09-24T21:27:45.223 回答
1

听起来您可能正在事件调度线程 (EDT) 上运行长时间运行的任务。看看 SwingWorker。如果您使用的是 1.6,它是内置的:

http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html

如果没有,您可以在以下位置找到更多信息:

http://en.wikipedia.org/wiki/SwingWorker

于 2009-09-24T21:31:19.910 回答