2010-03-08 39 views
2

我一直在使用以下方法創建組件並從Swing返回到/從EDT外部返回值。例如,下面的方法可以是一個擴展JFrame,以創建JPanel並將其添加到父JFrame使用invokeAndWait從Swing返回值

public JPanel threadSafeAddPanel() { 

    final JPanel[] jPanel = new JPanel[1]; 

    try { 
     EventQueue.invokeAndWait(new Runnable() { 
      public void run() { 
       jPanel[0] = new JPanel(); 
       add(jPanel[0]); 
      } 
     }); 
    } catch (InterruptedException ex) { 
    } catch (InvocationTargetException ex) { 
    } 

    return jPanel[0]; 
} 

本地1-長度陣列被用來從Runnable內部傳送「結果」 ,這在EDT中被調用。那麼,它看起來「有點」哈克,所以我的問題:

  1. 這是否有道理?其他人在做這樣的事嗎?
  2. 1長度數組是傳遞結果的好方法嗎?
  3. 有沒有更簡單的方法來做到這一點?

回答

1
  • 吞嚥異常,甚至沒有記錄他們:壞! - 當你經過2個小時的尋找錯誤之後遇到類似的事情時,你會恨自己
  • 不,陣列不是一個好方法;一方面,它提供了調用代碼沒有簡單的方法來等待EDT線程讀取結果之前執行Runnable
  • 有明確設計爲這種事情一類:SwingWorker
+0

1.你說得對:-) 2.好的,但invokeAndWait這樣做。 3.也許我應該使用它,但對於簡單的「吸氣劑」來說,這有點矯枉過正。 – 2010-03-08 13:50:17

+0

2.哦,對了,那個沒有註冊。 – 2010-03-08 13:52:19

+2

1. SwingWorker不是您可以用來修復Swing應用程序中的所有線程問題的錘子。 2. SwingWorker是用於在後臺線程上運行的東西,但這個問題是關於創建一個面板,它必須在EDT上運行 - 與SwingWorker可以幫助您完成的操作完全相反。 – Trejkaz 2014-03-21 02:07:24

0
  1. a)它是有道理的。 b)不是我所知道的。
  2. 和任何一樣好。
  3. invokeAndWait電話

之外創建的JPanel //這行加入到降價安撫

public JPanel threadSafeAddPanel() { 
    final JPanel jPanel = new JPanel(); 
    try { 
     EventQueue.invokeAndWait(new Runnable() { 
      public void run() { 
       add(jPanel); 
      } 
     }); 
    } catch (InterruptedException ex) { 
    } catch (InvocationTargetException ex) { 
    } 
    return jPanel; 
} 
+2

雖然3.最有可能的作品,它不嚴格地說是允許的。 – 2010-03-08 14:26:01

+1

我同意Joonas在美國東部時間以外創建Swing組件創造了一個不好的先例,應該避免。 – Nemi 2010-03-08 16:08:32

3

雖然這方法在某些情況下可能是有意義的,但在大多數情況下它是無用的。

原因在於,由於用戶操作(菜單項或按鈕單擊)始終從EDT執行,所以大多數(如果不是全部)組件的創建總是從EDT執行。

如果您在創建面板之前需要完成大量工作並且您不想阻止EDT,那麼您應該像其他人所建議的那樣,使用SwingWorker或Swing框架來支持長時間任務(通常基於SwingWorker內部,但不一定)。

關於你的問題2,可惜你沒有太多的方法可以做到這一點:

  • 使用,你做了1項陣列,這是 最簡單也最醜陋的解決方案
  • 創建ItemHolder類(請參閱下面的 ),幾乎相同, 需要更多的工作,並且是 更清潔,在我看來
  • 最後,使用java.util。併發 設施(未來和Callable); 這將是cleaniest我認爲, 而且它需要最大的努力

這裏被簡化,該ItemHolder類:

public class ItemHolder<T> { 
    public void set(T item) {...} 
    public T get() {...} 
    private T item; 
} 
+0

對此處關於忽略線程問題的建議+1,因爲無論如何,這種方法將被稱爲EDT。我只是斷言isEventDispatchThread()並刪除所有樣板文件 - 將問題推遲到有人從另一個線程實際調用它時,因爲YAGNI。 – Trejkaz 2014-03-21 02:09:30

0

可以輕鬆地檢查,看是否當前線程美國東部時間,然後執行正確,更簡單的情況下。至於使用最終數組獲取返回值,那麼當你不得不使用這樣的匿名內部類時,這是最簡單的方法。

public JPanel threadSafeAddPanel() throws InterruptedException, 
     InvocationTargetException { 
    if (EventQueue.isDispatchThread()) { 
     JPanel panel = new JPanel(); 
     add(panel); 

     return panel; 
    } else { 
     final JPanel[] jPanel = new JPanel[1]; 
     EventQueue.invokeAndWait(new Runnable() { 
      public void run() { 
       jPanel[0] = new JPanel(); 
       add(jPanel[0]); 
      } 
     }); 

     return jPanel[0]; 
    } 
}