2013-03-19 46 views
2

我的程序中有3個主類。第一個擴展applet(作爲我的主要),第二個是一個線程(實現Runnable),用於處理後端物流/與服務器的通信,第三個是JPanel類,它創建GUI(這是創建的在主線程(小程序)中調用SwingUtilities.invokeAndWait()的新線程如何使用wait()和notifyAll()在GUI類和邏輯線程之間進行通信

GUI類與後端線程多次通信以獲取數據以顯示在屏幕上我的問題是GUI在後端類提供數據之前顯示它的組件,所以我想告訴GUI在另一個線程中調用一個方法,等待它回聲,然後顯示它的組件。變體:

Object[] data = backend.Method1(); 
wait(); 
showComponents(data); 

在GUI類中,並將notifyAll();置於後端線程中Method1的底部,但我在netbeans中發出警告(在同步上下文之外調用Object.wait),並在程序崩潰時遇到java.lang.illegalmonitorstateexception運行。我已經嘗試將​​關鍵字添加到這兩種方法,但這會導致程序凍結。

我(很明顯,我敢肯定)只是在學習多線程:我在這裏誤解了什麼?

我有一種感覺,認爲它的JPanel類沒有實現runnable。

編輯:根據@ MadProgrammer的建議,我正在使用一個SwingWorker,它似乎在做伎倆。謝謝你指點我,我從來沒有聽說過他們。

final JLabel loading = new JLabel("loading"); 
    loading.setVisible(true); 
    add(loading); 

    SwingWorker sw = new SwingWorker<Map<String, ArrayList<Time[]>>, Void>() { 
     @Override 
     public Map<String, ArrayList<Time[]>> doInBackground(){ 
      System.out.println("doing"); 
      Map<String, ArrayList<Time[]>> toReturn = dbh.getTimes(specToPass); 
      return toReturn; 
     } 

     public void done(){ 
      try { 
       loading.setVisible(false); 
       Map<String, ArrayList<Time[]>> weekMap = new HashMap(this.get()); 
       showTimes(weekMap); 
      } catch (InterruptedException ex) { 
       ex.printStackTrace(); 
      } catch (ExecutionException ex) { 
        ex.printStackTrace(); 
      } 
     } 
    }; 
    sw.execute(); 

我希望你能讓我知道如果我沒有正確實施這個。再次感謝。

回答

5

請勿。以任何方式阻止用戶界面總是一個壞主意。這會使你的應用程序「掛起」,並阻止UI被更新(或者響應來自用戶的任何輸入)。

這會造成非常不好的用戶體驗。

而是使用某種回調,允許數據線程根據需要將更新發送回UI。這應該允許UI在等待數據線程中的數據時顯示「等待」消息。

您也可以使用SwingWorker來處理數據收集,但它可能會讓您滿足所有需求,但它提供了將任何更新同步到UI的簡單方法。

確保所有與UI的創建/修改/交互都是在事件分派線程的上下文中完成的。

看看Concurrency in Swing更多細節

更新

的基本工作流程(恕我直言)應該是這個樣子?

  • UI - 從後臺線程請求數據,通過一個偵聽器接口 到後臺線程(與像loadingDoneloadingFailed方法〔實施例
  • UI - 顯示「裝載」消息可以顯示一個很好的動畫GIF
  • 螺紋 - 當數據被加載(假設它一切順利),封裝該數據並將其傳遞迴經由loadingDone方法
  • UI - 當loadingDone被調用時,重新同步與EDT(使用SwingUtilities.invokeLater)並更新UI。

這實際上與SwingWorker更簡單,它會提供內置的

+0

如果我打破了GUI的方法分爲兩個最新進展 - 一個調用在後臺線程的方法,並顯示加載窗口。然後,在後臺線程的方法底部,讓它在GUI線程上調用第二個方法,它隱藏加載窗口並顯示組件?這看起來好像會起作用,但我恐怕它有點難看? – drewmoore 2013-03-19 05:55:39

+0

哇!您在短短5分鐘內閱讀/理解這7個網頁? Legend .. – 2013-03-19 05:58:35

+0

你的用戶界面應該調用後臺線程來獲取數據,並將其引用到類似於具有'loadingDone'和'loadingFailed'等方法的接口。然後你應該在用戶界面上顯示「等待」消息,也許使用一個漂亮的動畫GIF或其他東西。當調用'loadingDone'(或'Failed')時。你必須將呼叫重新同步到EDT(使用'SwingUtilities.invokeLater',然後將數據推送到用戶界面。就我個人而言,我會通過'loadingData'方法傳回數據 – MadProgrammer 2013-03-19 05:59:00

相關問題