Swingworker.done()在完成后冻结GUI几秒钟

时间:2013-03-24 22:25:05

标签: java multithreading swing swingworker event-dispatch-thread

我有一个SwingWorker,它在后台读取和处理文件,然后在JTextPane中格式化并显示各种样式的数据。

如果文件很大(超过200K),我将显示一个带进度条的对话框。在SwingWorker的done()方法中,我填充了JTextPane,然后隐藏了对话框。 done()方法如下所示:

protected void done() {
   populateTextPane();

   hideProgressDialog();
   System.out.println("After hideProgressDialog");
}

当它运行时,我会在控制台看到对话框消失和println消息,但GUI再冻结10-15秒,数据在冻结结束时在JTextPane中可见。 / p>

我认为在done()方法中发生的任何事情都会发生在Event Dispatch Thread中。但显然JVM正在产生另一个线程来隐藏对话框并在填充JTextPane时执行println。我希望显示进度对话框,直到GUI准备再次接受用户输入...如何检测done()中的所有内容何时完成?

2 个答案:

答案 0 :(得分:6)

{1}}方法在EDT上执行。如果您对此表示怀疑,可以随时使用done方法进行检查。

可能的解释是EventQueue.isDispatchThread()方法计划在EDT上重新绘制populateTextPane()。这意味着在您在用户界面中看到JTextPane方法的结果之前,done()方法已完成。

您可以尝试重写populateTextPane()方法,如下所示

done

这将确保protected void done() { populateTextPane(); SwingUtilities.invokeLater( new Runnable(){ @Override public void run(){ hideProgressDialog(); System.out.println("After hideProgressDialog"); } } ); } 仅在EDT上任何可能的hideProgressDialog Runnable日程表之后执行。但是,这仍然会冻结您的UI 10-15秒。唯一的区别是进度对话框仍然可见。

如果进度对话框显示在populateTextPane()之上,则不确定这是否有效。 JTextPane可能决定仅在对话框不可见后重新显示RepaintManager(因此不再隐藏JTextPane)。

答案 1 :(得分:1)

听起来像populateTextPane是EDT上一个长期运行的过程 - 你不想要它。尝试将其拆分:SwingWorker支持发布中间结果。

这样的东西
@Override
public Void doInBackground() throws Exception {
    ...
    while (!reader.isReady()) {
        publish(reader.readLine());
    }
    return null;
}

@Override
protected void process(List<String> lines) {
    for(String line: lines) {
        textPane.append(line);
    }
}