1

我有一個SwingWorker,它在後臺讀取並處理文件,之後它在JTextPane中使用各種樣式格式化和顯示數據。Swingworker.done()在完成後將GUI凍結幾秒

如果文件很大(超過200K),我將顯示一個包含進度條的對話框。在SwingWorker的done()方法中,填充JTextPane,然後隱藏對話框。完成()方法是這樣的:

protected void done() { 
    populateTextPane(); 

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

當它運行時,我會看到對話框消失,在控制檯中的println消息,但隨後的GUI凍結另外大約10-15秒,用數據在凍結結束時在JTextPane中可見。

我認爲done()方法中發生的任何事情都會發生在Event Dispatch Thread中。但顯然JVM正在產生另一個線程來隱藏對話框並在填充JTextPane時執行println。我想保持顯示進度對話框,直到GUI準備好再次接受用戶輸入爲止......如何檢測done()中的所有內容何時完成?

回答

6

done方法在EDT上執行。如果您懷疑這一點,您可以隨時使用EventQueue.isDispatchThread()方法進行檢查。

可能的解釋是populateTextPane()方法計劃在EDT上重新繪製JTextPane。這意味着done()方法已完成,然後才能在UI中看到populateTextPane()方法的結果。

你可以嘗試重寫done方法如下

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

這將確保hideProgressDialog在EDT任何可能RunnablepopulateTextPane()時間表後才能執行。但是,這仍然會凍結您的用戶界面10-15秒。唯一的區別是進度對話框仍然可見。

不確定如果進度對話框顯示在JTextPane之上,這是否會起作用。 RepaintManager可能決定僅在對話框變爲不可見後重新繪製JTextPane(因此不再隱藏JTextPane)。

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); 
    } 
} 
+0

的數據是一個很大的層次結構,以及它將如何看是不是真的知道,直到整個背景處理完成。它不適合以線性順序零散發布。但是,也許我可以通過在處理完數據後在後臺線程中構建StyledDocument來獲得某些東西,然後將完成的文檔分配給EDT中的JTextPane,而不是在EDT中的文檔已經駐留在JTextPane中時直接更新文檔。 – Gigatron 2013-03-25 14:51:35

+0

如果'populateTextPane'長時間運行,爲什麼'System.out'調用會被執行並且UI會在之後凍結? – Robin 2013-03-25 15:53:16

+0

@Robin - 沒有來自OP的進一步細節,你的猜測(某事得到安排)與其他任何方式一樣有效:-) – kleopatra 2013-03-25 16:00:35