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

Java Swing 實作類比時鐘:JFrame 繪圖、系統時間同步與動畫迴圈

     編輯:Java 相關知識

使用 Swing JFrame 繪製一個會走動的類比時鐘,是學習 Java 2D 繪圖、執行緒動畫迴圈與三角函數應用的經典練習。本文提供完整可執行程式碼,涵蓋 **自訂 JPanel 繪製表盤/指針、Calendar 取得系統時間、Thread.sleep 動畫迴圈、雙緩衝防閃爍** 等核心技術。

完整程式碼:AnalogClock

import javax.swing.*;
import java.awt.*;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class AnalogClock extends JFrame {

    public AnalogClock() {
        setTitle("類比時鐘");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(320, 360);
        setLocationRelativeTo(null);
        setResizable(false);
        add(new ClockPanel());
        setVisible(true);
    }

    public static void main(String[] args) {
        // 確保在 EDT 建立 UI
        SwingUtilities.invokeLater(AnalogClock::new);
    }

    // 內部類別:時鐘面板
    static class ClockPanel extends JPanel {
        private int hour, minute, second;

        public ClockPanel() {
            // 雙緩衝預設開啟,減少閃爍
            new Thread(this::animationLoop, "Clock-Animation").start();
        }

        private void animationLoop() {
            while (true) {
                updateTime();
                repaint(); // 觸發 paintComponent
                try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
            }
        }

        private void updateTime() {
            Calendar cal = new GregorianCalendar();
            hour = cal.get(Calendar.HOUR_OF_DAY);   // 24 小時制
            minute = cal.get(Calendar.MINUTE);
            second = cal.get(Calendar.SECOND);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            int w = getWidth(), h = getHeight();
            int cx = w / 2, cy = h / 2;
            int radius = Math.min(w, h) / 2 - 10;

            // 1. 表盤外圈
            g2.setColor(Color.BLACK);
            g2.drawOval(cx - radius, cy - radius, 2 * radius, 2 * radius);

            // 2. 刻度數字 12/3/6/9
            g2.setFont(new Font("SansSerif", Font.BOLD, 14));
            g2.drawString("12", cx - 6, cy - radius + 18);
            g2.drawString("3", cx + radius - 14, cy + 5);
            g2.drawString("6", cx - 4, cy + radius - 8);
            g2.drawString("9", cx - radius + 6, cy + 5);

            // 3. 秒針(紅、最長)
            drawHand(g2, Color.RED, radius * 0.85f, second, 60);

            // 4. 分針(藍、中等)
            drawHand(g2, Color.BLUE, radius * 0.65f, minute, 60);

            // 5. 時針(綠、最短,需疊加分鐘偏移)
            float hourAngle = (hour % 12 + minute / 60f) * 30f; // 30 度/時
            drawHand(g2, Color.GREEN, radius * 0.5f, hourAngle, 360);

            // 6. 數位時間顯示
            g2.setColor(Color.BLACK);
            g2.setFont(new Font("Monospaced", Font.BOLD, 16));
            String digital = String.format("%02d:%02d:%02d", hour % 12 == 0 ? 12 : hour % 12, minute, second);
            g2.drawString(digital, cx - 35, cy - radius - 10);
        }

        /** 繪製單根指針
         * @param g2 繪圖上下文
         * @param color 顏色
         * @param length 長度
         * @param value 當前值(秒/分/時角度)
         * @param maxValue 最大值(60 或 360) */
        private void drawHand(Graphics2D g2, Color color, float length, float value, float maxValue) {
            double rad = Math.toRadians(90 - (value * 360 / maxValue)); // 12 點鐘方向為 0 度,順時針
            int x = cx + (int) (length * Math.cos(rad));
            int y = cy - (int) (length * Math.sin(rad));
            g2.setColor(color);
            g2.setStroke(new BasicStroke(2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            g2.drawLine(cx, cy, x, y);
        }
    }
}

關鍵技術點解析

技術說明
自訂繪圖繼承 JPanel 覆寫 paintComponent(Graphics),所有繪圖邏輯集中於此
雙緩衝Swing 預設開啟雙緩衝,無需手動實作,有效消除閃爍
抗鋸齒g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON) 讓指針圓滑
三角函數換算角度 → 弧度 → 向量:x = cx + r*cos(θ), y = cy - r*sin(θ)(Y 軸向下)
時針平滑移動hour % 12 + minute/60.0 讓時針隨分鐘連續轉動,而非跳躍
動畫迴圈獨立執行緒 Thread.sleep(1000) + repaint(),非阻塞 EDT
EDT 安全主程式用 SwingUtilities.invokeLater 啟動 UI

進階擴充建議

  • 加入 **滑鼠拖曳移動視窗**(無邊框視窗 setUndecorated(true))。
  • 支援 **24/12 小時制切換**、**時區選擇**。
  • 使用 Timer 替代 Thread.sleep,簡化執行緒管理。
  • 繪製 **刻度線**(每分鐘/每小時細長線)增強真實感。
  • 封裝為 **Java Bean** 元件,支援屬性綁定(顏色、大小、字型)。

此類比時鐘練習完整串聯了 Swing 繪圖、幾何數學與多執行緒動畫,是 GUI 程式設計的優質入門專案。

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