2010-11-19 89 views
5

我有這個在EDT中被調用的ActionListener。我的plot()函數在計算量上很大,很容易花費五秒鐘。它使GUI按預期掛起。我添加了SwingUtilities.invokeLater的代碼,它仍然掛起。現在我不能爲我的升沉計算產生一個單獨的線程來響應GUI嗎?即使使用SwingUtilities.invokeLater後,爲什麼我的GUI仍然掛起?

final ActionListener applyListener = new ActionListener() 
     { 
      @CommitingFunction 
      public void actionPerformed(ActionEvent arg0) 
      { 
       /*Don't do plotting in the EDT :)*/ 
       SwingUtilities.invokeLater(new Runnable() 
       { 
        public void run() 
        { 
         plot(); 
        } 
       }); 
      } 
     }; 

回答

15

根本沒有。 InvokeLater不會生成新線程。 invokeLater exists to tell Swing explicitly "use the Event Dispatching Thread for this, but not right now". invoke和invokeLater的存在讓你可以只對其他線程進行事件派發線程安全的操作,而不是在這些線程上執行它們,而是告訴EDT來執行操作。

您的ActionListener將運行得非常快,將Runnable引發到Swing的事件派發隊列中。然後,當它達到那麼遠時,將需要五秒鐘來運行plot()。

唯一的解決方法是重構plot()。使用SwingWorker(或類似的多線程策略,但SwingWorker可能是最好的),以將plot()的邏輯實際移動到不同的線程上。該線程不能安全地繪製任何東西,因爲它不是Swing事件派發線程,所以它的所有繪製操作都需要通過invokeLater()來執行。出於效率原因,您應該嘗試使用一次invokeLater(),一次執行所有繪圖操作,並使用計算結果中存儲的結果。

+1

所以做我想要做的情節()的代碼運行在擴展一個類SwingWorker,然後在doInBackground()函數中運行這個計算繁重的代碼,然後使用done()函數來刷新我的顯示?在計算髮生時,我的GUI仍然處於活動狀態? – smuggledPancakes 2010-11-19 18:03:04

+0

@ user464095:是的,確切地說。 – ColinD 2010-11-19 18:06:24

+1

賓果。這就是SwingWorker的功能和用途。 – 2010-11-19 18:07:09

1

invokeLater將任務添加到GUI工作隊列。它將在所有其他任務執行後被調用,但它仍然使用GUI線程。

我建議你看看使用ExecutorService。

正如@Adam所說,它所做的任何實際繪圖都需要通過invokeLater完成。

1

您不會顯示plot()函數內部的內容,但您應該在而不是中放置任何繪畫。在新線程中計算任何你想要的東西,然後在EDT中進行繪畫。要做到這一點,最好使用SwingWorker

3

你正在做的和你認爲的相反。除了在EDT之外運行你的計算線程,你明確地稱它爲它在之內!

SwingUtilities.invokeLater()在稍後的EDT中排隊調用runnable!您想用SwingWorker代替。

1

以下是我爲我公司的應用程序所做的工作,由於法律原因,這是一些僞代碼,但問題是,如果屏幕無響應,它將重新啓動GUI。每當您使用SwingUtilities啓動EDT時,在同一個初始化塊中創建兩個觀察器線程。一個線程只會使用Swing實用程序在EDT線程上執行一個操作。另一個線程將監視第一個線程,看看是否感覺第一個線程有響應。如果第一個線程可以執行一個非常簡單的命令,它只會承認響應。

集isEDTCheck爲true在正常運行方式時,假在調試模式(否則你會不斷地得到重啓。

if (isEDTCheck) { 
     new Thread("EDTHeartbeat") { 
      @Override 
      public void run() { 
       Runnable thisThingYouDo = new Runnable() { 
        public void run() { 
         int x = 0; 
        } 
       }; 
       while (true) { 
        // first thread says we are waiting, aka bad state 
        edtwait=true; 
        try { 
         javax.swing.SwingUtilities.invokeAndWait(thisThingYouDo); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } catch (InvocationTargetException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        // first thread says we are not waiting, good state 
        edtwait=false; 
        try { 
         Thread.sleep(5000); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
      } 
     }.start(); 

     new Thread("EDTValidator") { 
      @Override 
      public void run() { 
       while (true) { 
        // is first thread in bad state? 
        if (edtwait) { 
         try { 
          Thread.sleep(3000); 
          // after 3 seconds are we still in bad state? if so, get rid of initial frame, pop up a dialog box in AWT that does no commands 
          if (edtwait) { 
           mainFrame.setVisible(false); 
           new Dialog(); 
          } catch (InterruptedException e) { 
          // TODO Auto-generated catch block 
          e.printStackTrace(); 
         } 
        } 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
      } 
     }.start(); 
    } 


    public class Dialog extends Frame { 
    private static final int WIDTH = 400; 
    private static final int HEIGHT = 300; 
    Frame f = null; 
    public Dialog() { 
     f = this; 
     hasSomethingBeenEntered=false; 
     this.setTitle("APP PROBLEM DETECTED"); 
     this.setSize(WIDTH, HEIGHT); 
     this.setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() - myapp.width, 0); 
     Panel p1 = new Panel() { 
      @Override 
      public void paint(final Graphics g) { 
       int left = Dialog.WIDTH/2 - 45; // don't use WIDTH shadowed by Panel class 
       int top = Dialog.HEIGHT/2 - 20; // same as above 
       g.drawString("APP HAS DETECTED A PROBLEM", left, top); 
      } 
     }; 
     this.add("Center", p1); 

     this.setAlwaysOnTop(true); 
       TextArea tb = new TextArea("APP HAS DETECTED A MAJOR PROBLEM\nIT WILL NOW RESTART IN 5 SECONDS"); 
     this.add(tb); 
     this.setVisible(true); 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     restartApp(); 

    } 

    private void restartApp() { 
      Runtime.getRuntime().exec("cmd /c start cmd.exe /K \"cd C:\\Progra~1\\Common~1 && C:\\Progra~1\\Common~1\\MyAppDir\\myjavaapp.jar\""); 
      System.exit(0); 
     } 
相關問題