2015-05-07 57 views
0

我在我的應用程序的主JFrame上有一個Window Listener。我在應用程序中的按鈕上也有一個按鈕監聽器。我用這個作爲按鈕偵聽模式:Swing Window監聽器線程問題

good.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent ev) { 
    // We're going to do something that takes a long time, so we 
    // spin off a thread and update the display when we're done. 
    Thread worker = new Thread() { 
     public void run() { 
     // Report the result using invokeLater(). 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
      for(int i=0; i<1000000; i++){ 
       System.out.println("foo"); 
      } 
      } 
     }); 
     } 
    }; 
    worker.start(); // So we don't hold up the dispatch thread. 
    } 
}); 

當我按一下按鈕,我看到每個迭代的打印輸出,但窗口監聽器不會被觸發後纔會循環完成執行。 print'foo'只是爲了模擬一些需要一段時間的事情,我希望一旦窗口事件發生(這可能在run()方法執行過程中的某個地方)就會觸發監聽器,但它好像它沒有被觸發,直到for循環結束。

任何想法爲什麼?

回答

3

Swing是單線程的 - Event Dispatch Thread(EDT)管理Swing的繪畫和事件。在長時間運行的任務完成之前,任何長時間運行的任務都會阻止EDT執行任務,換句話說,UI看起來就像鎖定了一樣。在這裏,您的代碼使用SwingUtilities將長時間運行的進程(for循環)分發到EDT上 - 如果您有一個長時間運行的任務並且在此過程期間需要響應Swing UI,請將長時間運行的任務放入其自己的Thread中,或者使用一個SwingWorker

+0

我的代碼是爲線程內部的動作偵聽器運行的。這不是你指的是什麼? – user1154644

+0

它位於線程內部,但線程僅使用SwingUtilities將該操作分派給EDT。目前還不清楚你究竟在做些什麼,但也許你想要在線程內部循環,以及在EDT上進行每次迭代更新。 – copeg

2

所以,這一切......

// Report the result using invokeLater(). 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
     for(int i=0; i<1000000; i++){ 
      System.out.println("foo"); 
     } 
     } 
    }); 

需要做的是,是導致循環事件調度線程的上下文中執行,這將阻止從美國東部時間處理事件隊列,包括繪畫請求。

在你的情況下,它可能是更容易使用SwingWorker,你可以用它來publish/process信息從後臺線程的EDT以及支持進度通知

詳情請參閱How to use SwingWorker