简体   繁体   English

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

[英]Swingworker.done() freezes GUI for several seconds after it's done

I have a SwingWorker that reads and processes a file in the background, after which it formats and displays the data with various styles in a JTextPane. 我有一个SwingWorker,它在后台读取和处理文件,然后在JTextPane中格式化和显示具有各种样式的数据。

If the file is large (over 200K), I'll display a dialog with a progress bar. 如果文件很大(超过200K),我将显示一个带有进度条的对话框。 In the done() method of the SwingWorker I populate the JTextPane and then hide the dialog. 在SwingWorker的done()方法中,我填充JTextPane,然后隐藏对话框。 The done() method looks like this: done()方法如下所示:

protected void done() {
   populateTextPane();

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

When it runs, I'll see the dialog disappear and the println message at the console, but then the GUI freezes for another 10-15 seconds, with the data becoming visible in the JTextPane at the end of that freeze. 当它运行时,我会在控制台上看到对话框消失和println消息,但是GUI冻结了另外10-15秒,冻结结束后,数据在JTextPane中变得可见。

I thought that whatever happened in the done() method would take place in the Event Dispatch Thread. 我以为,done()方法中发生的任何事情都会在事件调度线程中发生。 But apparently the JVM is spawning another thread to hide the dialog and execute the println while populating the JTextPane. 但是很显然,JVM在填充JTextPane的同时生成了另一个线程来隐藏对话框并执行println。 I want to keep the progress dialog displayed until the GUI is ready to accept user input again ... how do I detect when everything in the done() is REALLY done? 我想一直显示进度对话框,直到GUI准备好再次接受用户输入为止……如何检测done()中的所有内容何时真正完成?

The done method is executed on the EDT. done方法在EDT上执行。 If you doubt this, you could always check this with the EventQueue.isDispatchThread() method. 如果您对此表示怀疑,则可以始终使用EventQueue.isDispatchThread()方法进行检查。

A possible explanation is that the populateTextPane() method schedules a repaint of the JTextPane on the EDT. 可能的解释是populateTextPane()方法计划在EDT上重绘JTextPane This would mean the done() method is finished before you see the results of the populateTextPane() method in your UI. 这意味着在您在UI中看到populateTextPane()方法的结果之前, done()done()方法。

You could try to rewrite the done method as follows 您可以尝试如下重写done方法

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

This will make sure the hideProgressDialog is only executed after any possible Runnable the populateTextPane() schedules on the EDT. 这将确保仅在EDT上任何可能的Runnable populateTextPane()调度之后才执行hideProgressDialog However, this will still freeze your UI for 10-15 seconds. 但是,这仍然会将您的UI冻结10-15秒。 Only difference is that the progress dialog is still visible. 唯一的区别是进度对话框仍然可见。

Not sure whether this will work if the progress dialog is shown on top of the JTextPane . 如果进度对话框显示在JTextPane顶部,则不确定是否可以使用。 The RepaintManager might decide to only repaint the JTextPane after the dialog became invisible (hence no longer hiding the JTextPane ). RepaintManager可能会决定只重绘JTextPane后的对话框成为无形的(因此不再隐藏JTextPane )。

Sounds like the populateTextPane is a long-running process on the EDT - which you don't want. 听起来populateTextPane在EDT上是一个长期运行的过程-不需要。 Try to split it up: SwingWorker has api supports publishing intermediate results. 尝试将其拆分:SwingWorker的api支持发布中间结果。

Something like 就像是

@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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM