2014-02-05 32 views
0

我正在學習Swing並創建了一個示例GUI。我試圖按照精確順序實現以下內容...Swing invokeandwait

  1. 用戶在某些文本字段中輸入文本。
  2. 用戶單擊「啓動」按鈕。
  3. 「啓動」按鈕被禁用。
  4. 後臺線程產生並處理來自文本字段的文本。
  5. 後臺線程完成。
  6. 「啓動」按鈕變爲啓用。

我想使用invokeandwait,如下所示,但我得到「無法從事件調度程序線程調用invokeAndWait」。我的主要方法是在同一個.class文件中,我不太確定「事件分派器線程」到底是什麼。對於這樣的事情最好的辦法是什麼,我需要在我的工作線程中設置某種警報以返回到「事件分派器線程」?

LaunchButton代碼

private void launchButtonActionPerformed(java.awt.event.ActionEvent evt) {            

     launchButton.setEnabled(false); 

     try { 
      java.awt.EventQueue.invokeAndWait(new MyTestThread()); 
     } catch (Exception e) { 
     } 

     launchButton.setEnabled(true);  

    } 

工作線程

public class MyTestThread extends Thread { 

    private int i = 0; 

    public void run() { 

     while (i < 5) { 

      try { 
       System.out.println(i++); 
       sleep(10); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

    } 

} 

工作線程

public class WorkerThread extends SwingWorker<Integer[], Void> { 

    @Override 
    public Integer[] doInBackground() { 

     System.out.println("Doing in background"); 

     for (int i = 0; i < 5; i++) { 
      try { 
       Thread.sleep(1000); 
       System.out.println("Doing in background" + i); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     return null; 
    } 

    @Override 
    public void done() { 
     System.out.println("Swingworker is Done"); 
    } 
} 

從我的事件指派線程啓動工作線程(EDT)

new WorkerThread().execute(); 
+0

不要阻塞EDT(Event Dispatch Thread) - 當發生這種情況時GUI將「凍結」。而不是調用'Thread.sleep(n)'爲長時間運行的任務實現'SwingWorker'。有關更多詳細信息,請參見[Swing中的併發](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。 –

回答

1

事件調度線程(EDT)是允許訪問Swing類的唯一線程,(幾乎所有)方法。 EDT的所有初始化和事件都由EDT執行。要在EDT中執行某些操作,您必須使用SwingUtilities.invokeLaterinvokeAndWait(這相當於EventQueue.invokeXXX)。這就是爲什麼所有Swing程序主要以SwingUtilities.invokeLater()開頭的原因:在EDT中執行GUI初始化。

雖然EDT很忙,但UI凍結,這就是爲什麼後臺線程有用。當你需要獨立於UI(計算,I/O,傳輸......)做大量工作時,你必須使用「工作線程」。

欲瞭解更多有關在Swing線程請參見本教程:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/

現在,你所要完成的是對的,但你所使用的工具都沒有。

您需要知道兩件事:如何處理事件(如按下按鈕)以及如何創建後臺線程。

對於第一個看到這個教程: http://docs.oracle.com/javase/tutorial/uiswing/components/button.html

你只需要一個ActionListener添加到一個按鈕,只要按鈕引發聽者的actionPerformed方法將被執行的事件,在EDT。

最少例如:

JButton button = new JButton("Test button"); 
button.addActionListener(new ActionListener() 
{ 
    public void actionPerformed(ActionEvent event) 
    { 
     System.out.println("The button was pressed."); 
    } 
} 

event變量包含有用的信息,例如event.getSource()返回投擲的情況下,在這種情況下,按鈕的對象。

現在當按下按鈕時你想要做的是創建一個工作線程。正如您在併發教程中看到的,工作線程是使用SwingWorker類創建的。在那裏你可以定義一段將在後臺線程中執行的代碼(在doInBackground()方法中)以及在後臺工作完成後(在done()方法中)在EDT中執行的一段代碼。

所以,你會想要做這樣的事情:

private static JButton _button; 

//... 
_button = new JButton("Test button"); 

_button.addActionListener(new ActionListener() 
{ 
    public void actionPerformed(ActionEvent event) 
    { 
     System.out.println("The button was pressed."); 
     _button.setEnabled(false); 
     SwingWorker worker = new SwingWorker() 
     { 
      @Override 
      protected Object doInBackground() throws Exception 
      { 
       //do something useful in the background thread 
       return null; 
      } 

      @Override 
      protected void done() 
      { 
       _button.setEnabled(true); 
      } 
     } 
     worker.execute(); 
    } 
} 

有很多的信息,在那裏這件事。閱讀這些類的Java參考資料,閱讀官方教程並在SO中進行搜索。另一個關於SwingWorkers的好教程是:http://www.javacreed.com/swing-worker-example/

+0

感謝您的詳細回覆!對不起,我遲到的回覆,自從我上一篇文章以來有一些東西出現......解決方案已附加到我原來的帖子 – Jason