在 ActionListener 中直接呼叫 go(),其中包含 while(true) 迴圈與 Thread.sleep(10),導致整個視窗凍結,無法重繪、無法響應按鈕。
Swing 為**單執行緒模型**,所有事件處理、繪圖均在 **Event Dispatch Thread (EDT)** 執行。go() 佔用 EDT 導致訊息佇列堵塞,無法處理 repaint()、滑鼠/鍵盤事件。
public void actionPerformed(ActionEvent e) {
// 啟動背景執行緒
new Thread(() -> {
go(); // 此處執行耗時迴圈
}, "Lottery-Loop").start();
}
// go() 內部需安全更新 UI 元件
public void go() {
while (true) {
if (isGo) {
String s = generateNumber();
// 必須在 EDT 更新 Swing 元件
SwingUtilities.invokeLater(() -> tf.setText(s));
}
try { Thread.sleep(10); } catch (InterruptedException ignored) {}
}
}
private SwingWorker worker = new SwingWorker<>() {
@Override
protected Void doInBackground() {
while (!isCancelled()) {
if (isGo) {
publish(generateNumber()); // 發送中間結果
}
try { Thread.sleep(10); } catch (InterruptedException ignored) {}
}
return null;
}
@Override
protected void process(List chunks) {
tf.setText(chunks.get(chunks.size() - 1)); // 只顯示最新
}
};
// 啟動
worker.execute();
// 停止
worker.cancel(true);
SwingUtilities.invokeLater、SwingWorker.publish/process 或 EventQueue.invokeLater。isCancelled()、interrupt()) 避免資源洩漏。