Swing界面「不響應事件」、「畫面不更新」通常源於事件處理方法佔用事件分發線程(Event Dispatch Thread, EDT)執行耗時操作。EDT負責所有Swing組件繪圖與事件分發,單線程規則要求:一旦組件實現(realized),所有影響組件狀態的代碼必須在EDT中執行。組件實現方式:調用頂層組件show()/pack()/setVisible(true),或將組件加入已實現容器。
// 錯誤:在事件處理中執行耗時操作,導致按鈕「卡住」
public void actionPerformed(ActionEvent e) {
textArea.setText("Please wait...");
try {
Thread.sleep(1000); // 模擬耗時任務
textArea.setText("Done.");
} catch (InterruptedException ex) { ex.printStackTrace(); }
}
執行時按鈕按下狀態持續1秒才彈起,期間界面凍結無法響應。
repaint()僅在事件隊列添加UPDATE事件,需等待當前事件處理結束才能分發,無法即時重繪。
textArea.setText("Please wait...");
paint(getGraphics()); // 強制重繪,按鈕視覺彈起
Thread.sleep(1000); // 但EDT仍被佔用,按鈕1秒內不可再次點擊
視覺上按鈕彈起,實際仍阻塞事件處理,非根本解決。
核心原則:事件處理方法僅負責啟動後台線程,立即返回EDT。後台線程完成任務後,通過SwingUtilities.invokeLater()將UI更新提交回EDT。
public void actionPerformed(ActionEvent e) {
textArea.setText("Please wait...");
new Thread(() -> {
try {
Thread.sleep(1000); // 耗時任務
final String result = "Done.";
SwingUtilities.invokeLater(() -> textArea.setText(result));
} catch (InterruptedException ex) { ex.printStackTrace(); }
}).start();
}
此法保證EDT始終空閒響應用戶操作,界面流暢不凍結,是Swing多線程編程的黃金法則。