2012-01-30 90 views
1

我目前正在開發一個在MySQL數據庫上執行查詢的工具,我目前正在接口上工作。JTextField未正確更新

當用戶點擊按鈕「連接」時,狀態欄(JTextField)文本應該更改爲「正在連接...」。這正常工作:

connectButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      statusBar.setText("Connecting..."); 
      } 
     } 
    }); 

我實現以連接到數據庫的函數,則「連接」按鈕被點擊:

connectButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      Class.forName("com.mysql.jdbc.Driver"); 
      statusBar.setText("Connecting..."); 
      connection = DriverManager.getConnection("jdbc:mysql://" + database); 
      } 
     } 
    }); 

在這種情況下,狀態欄的文本不會更改到「正在連接...」,直到建立連接。

爲了提高可讀性,我刪除了一些代碼,如異常處理。

如何在連接建立之前強制更改狀態欄的文本?

+0

Kosir:這裏是[併發在Swing]中的教程(http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。問候 – 2012-01-31 03:54:23

回答

4

建立數據庫連接不應該在事件派發線程中執行。這阻止了組件的更新。相反,在後臺線程中執行任務。

如果您需要在執行此操作時報告結果,請使用SwingWorker類,或使用SwingUtilities類更新組件,特別是invokeLater。這些都將確保組件在EDT上得到更新,並且長期運行的任務將在其他地方進行。

欲瞭解更多信息,請閱讀Concurrency in Swing

+0

好的,謝謝。我想我需要學習如何使用SwingWorker。你能推薦我任何好的教程或簡單的例子嗎? – 2012-01-30 21:28:06

+0

您不需要*使用'SwingWorker',您只需*瞭解Swing線程模型。 :D – mre 2012-01-30 21:30:09

1

這是因爲您正在EDT(AWT事件調度線程)中建立連接。在進行連接時,不再需要更新,處理用戶輸入和重新繪製屏幕上的窗口(以圖形方式)。這意味着整個應用程序似乎被凍結,直到連接建立。
所以要解決這個問題,你必須在另一個線程中建立連接。另一個骯髒的,不推薦的方法是在更改文本後強制EDT重新繪製屏幕。這是最簡單的工作方式,但不是整潔的方式。

這可以通過調用repaint();然後調用update(getGraphics());來完成。但它很髒非常。我認爲你的屏幕會閃爍。但這很好地證明了這個問題。首先進行測試以瞭解實際發生的情況可能很有趣。

2

這個問題每兩天問一次。

如果您在事件派發線程中執行代碼,則會阻止此線程,從而阻止其執行其所有重新繪製操作,以使文本出現在文本字段中。

長時間運行的阻塞任務應在後臺線程中運行,並且此線程不得訪問Swing組件。使用SwingWorker。它的javadoc解釋了一切。它還有一個鏈接到Swing教程的相關部分,你應該閱讀。

3

正如其他人所說的,連接邏輯最好在除事件調度線程以外的線程上執行。但是,從技術上講,這不是在連接建立之前文本字段沒有更新的原因。

實際之所以發生這種情況是,在內部Swing組件使用數據結構來存儲的聽衆(在這種情況下ActionListener多個),由此在聽衆相反的順序通知相比,加入它們的順序。因此,在您的示例中,創建連接的ActionListener會在負責更新文本的偵聽器之前通知。

一個簡單的修復方法是將兩個ActionListener合併成一個代碼塊;沒有理由需要添加多個偵聽器。這當然會導致你的GUI在連接嘗試進行時被阻塞,這就是爲什麼其他人建議使用諸如SwingWorker這樣的機制來防止這種情況。

connectButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
    statusBar.setText("Connecting..."); 

    new SwingWorker<Void, Void>() { 
     protected Void doInBackground() { 
     // Called on a background thread. 
     connectToDatabase(); 
     return null; 
     } 

     protected void done() { 
     // Called on Event Dispatch thread once connect routine has completed. 
     try { 
      get(); // Propagate any exceptions back to Event Dispatch thread. 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
      JOptionPane.showMessageDialog(null, 
      "Failed to connect: " + ex.getMessage(), 
      "Error", 
      JOptionPane.ERROR_MESSAGE); 
     } 
     } 
    }.execute(); 
    } 
}); 
+0

我只有一個監聽器。我只是指定了多個,所以你可以理解我的問題。 – 2012-01-30 21:56:36