2014-09-06 32 views
2

使用EventQueue.invokeLater(例如,從長時間運行的後臺非EDT線程進程生成的輸出)執行更新我的swing GUI不同於用戶單擊的位置的所有處理器。處理長時間運行的JEditorPane setText進程的最佳做法

在我當前的場景中,我有一個TCPIP套接字讀取後臺線程進程,它返回需要更新JEditorPane對象的數據。我使用JEditorPane setText調用。問題是,將setText調用放在invokeLater例程中會凍結大文件的GUI(例如案例測試19,790 KB)。

我試圖解決這個問題是在非EDT後臺線程中執行setText操作。這似乎解決了這個問題,但是,我擔心最佳實踐,因爲Java 7中的JEditorPane setText(我正在使用的JDK)不是線程安全的。但是,在我看來,這裏執行的冗長過程在JDK的DefaultEditorKit.read中,並且在該方法內,唯一會影響GUI的代碼位於doc.insertString調用中(除非我我錯了)。現在,當您查看JDK的PlainDocument.java insertString方法時,它會記錄IT是線程安全的,因此可以認爲此解決方案是合理的。

無論其...

壓力測試我的申請,我周圍的GUI一些隨機點擊,目前有一個樹節點動畫的運行,和下面的大負荷期間,確實出現了動畫放慢有一點,因此我擔心我沒有執行最好的解決方案(也很關心未來的JRE在這裏搞砸我,因此不依賴於當前正在使用線程安全的insertString)。

我已經調查過並看到這個問題「如何處理長時間運行的JEditorPane setText」之前已經被問過,但沒有合適的答案。

問題1)有沒有人對我目前的觀察有想法?

問題2)有沒有人有關於如何實現這個另一個想法?

注意JEditorPane是我唯一的選擇,因爲我最終將支持動態字體的IDE外觀和感覺。

還要注意下面的調用在EventQueue.invokeLater例程中調用,所以最初的editorPane工作在EDT中。

public void updateBigDataEditorPane(final JEditorPane editorPane, final String inStr) { 
    // Update editor object and content. 
    editorPane.setContentType("text/plain"); 
    editorPane.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N 
    editorPane.setDocument(editorPane.getEditorKit().createDefaultDocument()); 
    // Content update. NOTE in non-EDT thread to stop GUI freeze with large content. 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      //// synchronized 
      synchronized(tabsLock) { 
       // Set content. 
       editorPane.setText(inStr); 
      } //// synchronized 
     } 
    }).start(); 
} 
+0

使用SwingWorker下載文本並使用它的方法來應用它... – MadProgrammer 2014-09-06 22:04:45

+0

@MadProgrammer SwingWorker將應用與上述相同的原理(並且一旦我建立了上述的正確性,我將把它改爲使用SwingWorker)。也就是說,setText是在後臺完成的,而不是在EDT中完成的(SwingWorker本質上就是這麼做的,對嗎?),那麼EDT中需要的任何後續操作都是在done方法中完成的。我假設這就是你的意思,因爲否則將setText放在SwingWorker done方法中會與我原來的問題代碼具有相同的效果 - 在EDT中執行setText會凍結GUI。思考? – 2014-09-07 18:46:09

+0

否。SwingWoker爲您提供發佈/處理方法,允許您使用EDT同步更新。事實是,您可以簡單地使用done方法,該方法在EDT中也被稱爲更新UI。請記住,Swing通常不是線程安全的。 – MadProgrammer 2014-09-07 21:25:26

回答

0

雖然提供的答案卻是有益的,並會被用來解決特定的長時間運行的線程EDT要求,我結束了使用該解決方案如下;

  1. 創建一個新的JEditorPane對象
  2. 執行耗時的setText調用
  3. 在規定時間內完成,用這個新創建的一個取代目前在GUI上活躍的JEditorPane對象。

使用SwingWorker執行後臺非EDT任務(1 & 2),然後在EDT線程完成時執行第3步。

0

您可以使用EditorPane的文件(通過editorPane.getDocument()),並執行這個文件的變更(通過insertString(...),而不是使用的setText(...))在另一個線程。

通過這樣做,你可以(種)動態地(意味着:在閱讀時)寫內容。

如例(從文件到Textpane添加文本,不結冰UI):
編輯:這個新的代碼測試,但它應該更好地展示我的建議...):

public void readFileAsync() 
{ 
    final String fileName = "/path/to/file.txt"; 
    final StyledDocument doc = yourTextPane.getStyledDocument(); 

    Runnable r = new Runnable() 
    { 
     public void run() 
     { 
      try 
      { 
       List<String> lines = Files.readAllLines(Paths.get(fileName), Charset.defaultCharset()); 
       for (String line : lines) 
       { 
        SwingUtilities.invokeLater(new Runnable() 
        { 
         public void run() 
         { 
          doc.insertString(doc.getLength(), line, null); 
         } 
        }); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    }; 
    Thread t = new Thread(r); 
    t.start(); 
} 
+0

線程合併狀態最近已經改變,這可能不是線程安全的... – MadProgrammer 2014-09-06 22:05:33

+0

@Ben在文檔上執行更改:如果通過EDT完成了與最初報告相同的GUI凍結問題。如果在EDT之外完成,則基本上成爲我最初提出的相同解決方案 - 唯一的區別是我的建議解決方案在EDT之外執行預先文檔插入操作(上面描述的setText和read中的代碼)。 – 2014-09-07 19:09:29

+0

@MadProgrammer現在,在我正在使用的JDK 7版本中,文檔insertString方法是線程安全的,如果上面的解決方案確實是合理的話,那麼我需要研究在後來的JRE上傳遞JDK7構建代碼的後果(I在這裏不會問這個問題,因爲我擔心我還沒有研究過這個問題)。 – 2014-09-07 19:12:06

相關問題