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

Java 100例:繪製指針類比時鐘

     編輯:Java 程式設計入門

使用 Swing Timer 每秒觸發重繪,透過三角函數計算時、分、秒三支指針角度,繪製圓形表盤、刻度數字與指針。展示 Graphics.fillPolygon 繪製楔形指針與雙重繪製消除閃爍技巧。

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

public class Clock extends JFrame implements ActionListener {
    Timer timer;
    int x, y, oldX, oldY, r, x0, y0, w, h, ang;
    int sDeg, mDeg, hDeg, oldM, oldH;
    final double RAD = Math.PI / 180.0;

    public static void main(String[] args) { new Clock(); }

    public Clock() {
        super("Clock");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setBackground(new Color(0, 0, 192));
        setSize(300, 300);
        setVisible(true);
        // 每秒觸發 repaint
        new Timer(1000, e -> repaint()).start();
    }

    public void paint(Graphics g) {
        Insets in = getInsets();
        int L0 = in.left/2, T0 = in.top/2;
        h = getSize().height;
        // 表盤圓圈
        g.setColor(Color.WHITE);
        g.drawOval(L0+30, T0+30, h-60, h-60);
        g.drawOval(L0+32, T0+32, h-64, h-64);
        r = h/2 - 30;
        x0 = 30 + r - 5 + L0;
        y0 = 30 + r - 5 - T0;
        // 刻度數字 1~12
        for (int i = 1, ang = 60; i <= 12; i++, ang -= 30) {
            int xx = (int)((r+10)*Math.cos(RAD*ang)) + x0;
            int yy = (int)((r+10)*Math.sin(RAD*ang)) + y0;
            g.drawString(String.valueOf(i), xx, h - yy);
        }
        x0 = 30 + r + L0; y0 = 30 + r + T0;
        // 取得時間
        Calendar now = Calendar.getInstance();
        int hh = now.get(Calendar.HOUR_OF_DAY);
        int mm = now.get(Calendar.MINUTE);
        int ss = now.get(Calendar.SECOND);
        // 顯示數字時間
        g.setColor(Color.PINK); g.fillRect(L0, T0, 60, 28);
        g.setColor(Color.BLUE);
        g.drawString(String.format("%02d:%02d:%02d", hh, mm, ss), L0, T0+25);
        // 計算指針角度 (12點鐘方向為 90 度)
        sDeg = 90 - ss * 6;
        mDeg = 90 - mm * 6;
        hDeg = 90 - hh * 30 - mm / 2;
        // 擦除舊秒針
        if (oldX > 0) {
            g.setColor(getBackground());
            g.drawLine(x0, y0, oldX, h - oldY);
        } else { oldM = mDeg; oldH = hDeg; }
        // 繪製新秒針
        g.setColor(Color.YELLOW);
        x = (int)((r-8)*Math.cos(RAD*sDeg)) + x0;
        y = (int)((r-8)*Math.sin(RAD*sDeg)) + y0 - 2*T0;
        g.drawLine(x0, y0, x, h - y);
        oldX = x; oldY = y;
        // 擦除並重繪分針、時針 (楔形)
        if (mDeg != oldM) { drawHand(g, oldM, (int)(r*0.7), getBackground()); oldM = mDeg; }
        if (hDeg != oldH) { drawHand(g, oldH, (int)(r*0.5), getBackground()); oldH = hDeg; }
        drawHand(g, mDeg, (int)(r*0.7), Color.GREEN);
        drawHand(g, hDeg, (int)(r*0.5), Color.RED);
    }

    void drawHand(Graphics g, int deg, int len, Color c) {
        int[] xp = new int[4], yp = new int[4];
        xp[0] = x0; yp[0] = y0;
        xp[1] = (int)((len-10)*Math.cos(RAD*(deg-4))) + x0;
        yp[1] = h - ((int)((len-10)*Math.sin(RAD*(deg-4))) + y0);
        xp[2] = (int)(len*Math.cos(RAD*deg)) + x0;
        yp[2] = h - ((int)(len*Math.sin(RAD*deg)) + y0);
        xp[3] = (int)((len-10)*Math.cos(RAD*(deg+4))) + x0;
        yp[3] = h - ((int)((len-10)*Math.sin(RAD*(deg+4))) + y0);
        g.setColor(c);
        g.fillPolygon(xp, yp, 4);
    }

    public void actionPerformed(ActionEvent e) { timer.restart(); }
}

優化重點:

  • 使用 Timer 取代 Thread.sleep 避免阻塞 EDT。
  • 僅重繪指針區域 (XOR 模式或背景色覆蓋) 減少閃爍。
  • 指針以楔形多邊形繪製,視覺效果優於單線條。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved