Swing API 設計目標:強大、靈活、易用。為簡化元件開發,不要求元件支援多執行緒存取,而是將所有請求集中在單一事件分發執行緒(EDT)中執行。
鐵律: 一旦 Swing 元件被「具現化」,所有可能影響或依賴元件狀態的程式碼,必須在 EDT 中執行。
paint() 方法已被或可能被呼叫。頂層視窗調用 setVisible(true)、show()、pack() 時具現化;加入已具現化容器也會觸發paint()、actionPerformed() 自動在 EDT 執行;SwingUtilities.invokeLater() 也可將程式碼排入 EDTThis method is thread safe...public static void main(String[] args) {
JFrame f = new JFrame("Labels");
// 加入元件...
f.pack(); // 此處具現化
f.show(); // 技術上不安全,但實際無paint回調發生
// 之後無GUI代碼,安全轉移至EDT
}
init() 中建構 GUI: 瀏覽器不會在 init()/start() 前繪製,故安全。但不得在其中調用 show()/setVisible(true);耗時操作應啟動獨立執行緒若需在事件處理/繪圖代碼外部存取 UI,必須使用:
SwingUtilities.invokeLater(Runnable):非同步排入 EDT,立即返回SwingUtilities.invokeAndWait(Runnable):同步等待 EDT 執行完成耗費大量計算或受 I/O 限制的工作,絕不可在 EDT 執行(會凍結 UI)。應使用:
SwingWorker:專為背景任務設計,支援進度回報、完成回調、中途取消Timer:週期性或延遲執行的輕量任務| 錯誤做法 | 正確做法 |
|---|---|
| 在背景執行緒直接修改元件狀態 | 用 invokeLater 送回 EDT |
| 在 EDT 執行耗時資料庫/網路操作 | 用 SwingWorker 背景執行,完成後 invokeLater 更新 UI |
主執行緒 show() 後繼續操作 GUI | show() 後不再操作 GUI,或用 invokeLater |