在 Swing 介面上每秒更新時間顯示,常見三種實作方式:
利用 java.util.Timer 排程固定頻率執行 TimerTask,精度較高,單一 Timer 可共享多個 Task。
public class TimeFrame extends JFrame {
private JLabel displayArea;
private static final int ONE_SECOND = 1000;
private static final String FORMAT = "HH:mm:ss";
public TimeFrame() {
displayArea = new JLabel();
add(new JLabel("CurrentTime: "), BorderLayout.WEST);
add(displayArea, BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(200, 70);
setLocationRelativeTo(null); // 置中顯示
configTimer();
setVisible(true);
}
private void configTimer() {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT);
@Override public void run() {
displayArea.setText(sdf.format(Calendar.getInstance().getTime()));
}
}, new Date(), ONE_SECOND);
}
public static void main(String[] args) { new TimeFrame(); }
}
實作 Runnable,在 while(true) 迴圈中 Thread.sleep(1000) 更新 UI。需注意 Swing 非執行緒安全,實務上應用 SwingUtilities.invokeLater 更新元件,但此簡易範例直接更新通常也能運作。
public class DTimeFrame2 extends JFrame implements Runnable {
private JLabel displayArea;
// ... 初始化同方法一 ...
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
while (true) {
displayArea.setText(sdf.format(Calendar.getInstance().getTime()));
try { Thread.sleep(1000); } catch (Exception e) { displayArea.setText("Error!!!"); }
}
}
public static void main(String[] args) {
DTimeFrame2 f = new DTimeFrame2(); f.setVisible(true);
new Thread(f).start();
}
}
結合 JComboBox 選擇時區,TimerTask 定時更新,展示 TimeZone、Locale、SimpleDateFormat 綜合應用。
public class WorldTimeFrame extends JFrame {
private JComboBox zoneBox;
private JLabel displayArea;
private TimeZone timeZone = TimeZone.getDefault();
private static final String FORMAT = "EEE d MMM, HH:mm:ss";
public WorldTimeFrame() {
zoneBox = new JComboBox<>(TimeZone.getAvailableIDs());
zoneBox.addActionListener(e -> timeZone = TimeZone.getTimeZone((String)zoneBox.getSelectedItem()));
displayArea = new JLabel();
add(zoneBox, BorderLayout.NORTH);
add(displayArea, BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack(); setLocationRelativeTo(null); setVisible(true);
new Timer().scheduleAtFixedRate(new TimerTask() {
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.ENGLISH);
@Override public void run() {
sdf.setTimeZone(timeZone);
displayArea.setText(sdf.format(Calendar.getInstance().getTime()));
}
}, new Date(), 1000);
}
public static void main(String[] args) { new WorldTimeFrame(); }
}
| 方法 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| Timer + TimerTask | 精度高、單 Timer 可管多 Task、非阻塞 | API 較舊 (Java 5+) | 一般定時 UI 更新、多任務排程 |
| Thread + sleep | 代碼直觀、無額外依賴 | 佔用一執行緒、sleep 精度受 OS 排程影響、需手動處理 Swing 線程安全 | 極簡單的單一任務、教學示範 |
| ScheduledExecutorService | 現代替代方案 (Java 5+)、支援池化、更靈活 | 代碼稍繁瑣 | 生產環境、需取消/調整排程、高併發定時任務 |
推薦: 一般 Swing 應用優先使用 Timer;生產環境或需更精確控制時,改用 ScheduledExecutorService。注意 setDefaultCloseOperation(EXIT_ON_CLOSE) 讓關閉視窗結束程式,setLocationRelativeTo(null) 讓視窗置中。