首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Swing 動態顯示時間三種實現:TimerTask、Thread 與世界時鍾完整代碼

     編輯:Java 相關知識

核心需求:GUI 界面實時更新時間

Swing 界面顯示動態時間是經典入門案例,核心挑戰:定時任務觸發 + 線程安全更新 UI。本文對比三種方案並提供可直接運行的完整代碼。

方案一:Timer + TimerTask(推薦)

Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
        // 必須在 EDT 線程更新 UI
        SwingUtilities.invokeLater(() -> timeLabel.setText(time));
    }
}, new Date(), 1000); // 立即執行,每 1 秒重複

優點:

  • 單線程處理多任務,資源開銷小
  • scheduleAtFixedRate 保證固定頻率,避免累積誤差
  • API 簡潔,適合簡單定時需求

注意:TimerTask.run() 在後台線程執行,更新 UI 必須用 SwingUtilities.invokeLater。

方案二:獨立 Thread + sleep(簡單直接)

new Thread(() -> {
    while (true) {
        String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
        SwingUtilities.invokeLater(() -> timeLabel.setText(time));
        try { Thread.sleep(1000); } catch (InterruptedException e) { break; }
    }
}).start();

缺點:

  • 每個時鐘佔用一個線程,擴展性差
  • sleep 精度低,長期運行有誤差漂移
  • 需自行處理線程中斷、異常退出

方案三:ScheduledExecutorService(企業級選擇)

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> 
    SwingUtilities.invokeLater(() -> timeLabel.setText(new SimpleDateFormat("HH:mm:ss").format(new Date()))),
    0, 1, TimeUnit.SECONDS);

優勢:線程池管理、支持延遲/周期、可取消、異常不會導致任務停止(Timer 會)。

完整可運行案例:世界時鍾

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import java.util.*;

public class WorldClock extends JFrame {
    private JLabel timeLabel = new JLabel("", SwingConstants.CENTER);
    private JComboBox zoneCombo = new JComboBox<>(TimeZone.getAvailableIDs());
    private TimeZone currentZone = TimeZone.getDefault();
    private final SimpleDateFormat fmt = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.ENGLISH);
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    public WorldClock() {
        setTitle("世界時鍾");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        
        timeLabel.setFont(new Font("Monospaced", Font.BOLD, 24));
        add(timeLabel, BorderLayout.CENTER);
        
        zoneCombo.addActionListener(e -> {
            currentZone = TimeZone.getTimeZone((String) zoneCombo.getSelectedItem());
            fmt.setTimeZone(currentZone);
            updateTime(); // 立即刷新
        });
        add(zoneCombo, BorderLayout.NORTH);
        
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        
        scheduler.scheduleAtFixedRate(this::updateTime, 0, 1, TimeUnit.SECONDS);
    }

    private void updateTime() {
        fmt.setTimeZone(currentZone);
        String time = fmt.format(new Date());
        SwingUtilities.invokeLater(() -> timeLabel.setText(time));
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(WorldClock::new);
    }
}

關鍵技術點總結

技術點 說明
EDT 線程安全 所有 UI 更新必須在 Event Dispatch Thread,使用 SwingUtilities.invokeLater
時區處理 TimeZone.getAvailableIDs() 獲取所有时区,SimpleDateFormat.setTimeZone() 切換
格式化模式 HH:mm:ss 24小時制,hh:mm:ss a 12小時制,z 顯示時區名
窗口居中 setLocationRelativeTo(null)
自適應大小 pack() 根據組件優先大小調整窗口

避坑指南

  1. 不要在 TimerTask/Thread 中直接 setText → 會導致界面卡死、異常或數據不一致
  2. SimpleDateFormat 非線程安全 → 每次格式化創建新實例,或使用 ThreadLocal,或 Java 8+ DateTimeFormatter(線程安全)
  3. 關閉窗口時關閉調度器 → 添加 WindowListener 調用 scheduler.shutdown()
  4. 高精度需求 → 使用 System.nanoTime() 計算下次執行時間,或引入 Joda-Time / java.time

掌握 Swing 定時更新模式,可輕鬆構建數字時鍾、倒計時器、實時監控儀表板等實用工具。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved