1

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

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

protected void done() {
   populateTextPane();

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

当它运行时,我会看到对话框消失并且控制台上的 println 消息,但随后 GUI 再冻结 10-15 秒,在冻结结束时数据在 JTextPane 中变得可见。

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

4

2 回答 2

6

done方法在 EDT 上执行。如果您对此表示怀疑,您可以随时使用该EventQueue.isDispatchThread()方法进行检查。

一种可能的解释是,该方法计划在 EDT 上populateTextPane()重绘。JTextPane这意味着该方法在您在 UI 中done()看到该方法的结果之前已经完成。populateTextPane()

您可以尝试重写done方法如下

protected void done() {
   populateTextPane();
   SwingUtilities.invokeLater( new Runnable(){
     @Override
     public void run(){
       hideProgressDialog();
       System.out.println("After hideProgressDialog");
     }
   } );
}

这将确保hideProgressDialog仅在 EDT 上的任何可能Runnable的计划之后执行。populateTextPane()但是,这仍会使您的 UI 冻结 10-15 秒。唯一的区别是进度对话框仍然可见。

如果进度对话框显示在JTextPane. RepaintManager可能决定只在对话框变得不可见后重新绘制(JTextPane因此不再隐藏JTextPane)。

于 2013-03-24T22:40:35.690 回答
1

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

就像是

@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);
    }
}
于 2013-03-25T08:20:46.357 回答