2012-08-06 48 views
9

我有幾個關於Swing和使用EDT進行GUI更新的問題。我剛開始閱讀這個東西,所以我在這方面是一個完整的初學者:Java Swing - 在EDT上運行

  1. 需要哪些操作在EDT上運行?如果他們不這樣做,簡直是一個異常提出?
  2. 有沒有什麼特定的時間,我們實際上在EDT自動?
  3. 如果我們使用SingUtilities.invokeLater安排任務,我們將它排入當前的GUI更新任務隊列嗎?
  4. 對上述隊列的訪問我猜是同步的,或者使用了一些併發集合,但是如果我從兩個後臺線程安排兩個GUI更新任務,那麼不可能說哪一個會先被添加?例如,如果線程1首先提交將JLable的文本設置爲「是」的任務,然後短時間後,第二個線程出現並提交將該值設置爲「否」的任務,那麼我們是否保證結果將是「是」,還是僅僅是操作系統如何安排這些事情的問題?
  5. SwingWorker如何確保done()方法在EDT上運行?它集下面的代碼:

    future = new FutureTask<T>(callable) { 
           @Override 
           protected void done() { 
            doneEDT(); 
            setState(StateValue.DONE); 
           } 
          }; 
    

所以我想知道是否FutureTask某種程度上確保了invokeLater叫?

感謝您的答案。

回答

14
  1. 一個很好的規則是所有操作(access/updates/...)都應該在EDT上進行。在javadoc中提到了一些例外(某些類的某些方法),但是他們很難記住,堅持'在萬事俱備'的方法更容易。異常不會被提出(幸運的是,JavaFX解決了這個缺點)。您可以使用自定義RepaintManager來檢測大多數這些違規:請參閱this article
  2. 在EDT上處理用戶觸發的所有內容。例如,如果用戶點擊一個按鈕,將在EDT上調用相應的ActionActionListeneractionPerformed
  3. 正確
  4. 您先安排的事情將首先執行。調用invokeLater只需在隊列末尾添加Runnable。稍後再次使用invokeLater將在先前計劃的Runnable之後添加此新的Runnable
  5. 看看代碼爲doneEDT

    private void doneEDT() { 
        Runnable doDone = 
         new Runnable() { 
          public void run() { 
           done(); 
          } 
         }; 
        if (SwingUtilities.isEventDispatchThread()) { 
         doDone.run(); 
        } else { 
         doSubmit.add(doDone); 
        } 
    } 
    
+0

兩個問題: 4.所以它是第一個執行後面調用的線程的權利?因此,OS可能會安排第二個後臺線程invokeLater調用FIRST,並且訂單會被搞亂? 5.我仍然沒有看到如何達到EDT。 do Submit將Runnable添加到AccumulativeRunnable ... – Bober02 2012-08-06 09:19:03

+0

@ Bober02請參閱由於使用Swing'Timer'而在EDT上執行的javax.swing.SwingWorker.DoSubmitAccumulativeRunnable runnable。對於4:是的,如果您想控制訂單,您必須確保您的一個後臺線程在其他線程安排其可運行之前安排可運行。 – Robin 2012-08-06 09:27:05

+1

有時,提交給doSubmit()的所有內容都在EDT中運行。你不必關心它是如何以及在哪裏完成的:這個類已經過測試,並且按照記錄進行工作。 – 2012-08-06 09:28:47

-1

在Java GUI應用程序,main()方法沒有長期居住,調度GUI的建設中的Event Dispatcher Thread之後,main()方法退出...現在其EDT負責處理圖形用戶界面。

2.所以我們並不需要開始在EDT,其自動完成我們的應用程序。

始終讓用戶界面工作在UI線程上,而非UI工作在非UI線程上。

因此,請始終保持您的EDT線程,這是僅供GUI工作的GUI線程。

如:

public static void main(String[] args){ 
    EventQueue.invokeLater(new Runnable(){ 
      public void run(){  
      myframe.setVisible(true); 
     } 
    } 
} 

4.創建一個單獨的非UI線程來處理長時間服用方法。

5.您可以簡單地使用Thread或使用SwingWorker這是特意引入的Java同步的UI和非UI線程。

6. SwingWorker不確保done()方法在EDT上運行,但將它的輸出同步到EDT線程(它是GUI線程)。

+2

運行你的觀點6:看到的SwingWorker的javadoc類別:事件分派線程:在此線程所有Swing相關的活動發生。 SwingWorker調用process和done()方法,並通知此線程上的任何PropertyChangeListener。 – Robin 2012-08-06 09:15:29

8
  1. 基本上,每次使用Swing組件或Swing組件的模型時,都必須在EDT中完成。如果你不這樣做,不會引發例外。它可以工作,但也可能無法工作,行爲不穩定,數據損壞等。
  2. 每個Swing事件偵聽器都在EDT中調用。基本上,除了主要的方法之外,默認情況下,Swing應用程序的每行代碼都在EDT中執行,除非您明確地啓動線程,使用SwingWorker或類似的東西。
  3. 是的。
  4. 提交給SwingUtilities.invokeLater()的任務按照與提交順序相同的順序執行。
  5. 它在內部使用SwingUtilities.invokeLater()或類似的方法。 FutureTask與Swing沒有任何關係。 SwingWorker確保其完成的方法在EDT中執行。 doneEDT()方法有以下注釋:在EDT上完成調用。
0

的SwingWorker確保完成()方法是在美國東部時間通過下面的代碼運行:

Runnable doDone = 
     new Runnable() { 
      public void run() { 
       done(); 
      } 
     }; 
    if (SwingUtilities.isEventDispatchThread()) { 
     doDone.run(); 
    } else { 
     doSubmit.add(doDone); 
    } 

其實它添加doDone變量到AccumulativeRunnable doSubmit,

查看AccumulativeRunnable.java的源代碼你會發現有有下面的代碼

保護無效提交(){

SwingUtilities.invokeLater(本);

}

這就是爲什麼SwingWorker的保證方法()完成對EDT