使用 Java AWT/Swing 繪製一個即時運行的類比時鐘,包含圓形錶盤、刻度數字、三針動畫(秒針每秒跳動、分針/時針平滑更新)、數字時間顯示與背景擦除防閃爍。代碼展示了圖形繪製、定時器驅動、三角函數座標計算等核心技術。
繼承 JFrame,實作 ActionListener,使用 javax.swing.Timer 每秒觸發重繪。
int r = h/2 - 30; // 半徑
int x0 = 30 + r + L0, y0 = 30 + r + T0; // 圓心
int ang = 60;
for (int i = 1; i <= 12; i++) {
int x = (int)((r + 10) * Math.cos(RAD * ang) + x0);
int y = (int)((r + 10) * Math.sin(RAD * ang) + y0);
g.drawString("" + i, x, h - y); // 繪製數字
ang -= 30;
}
Calendar now = Calendar.getInstance();
int hh = now.get(Calendar.HOUR_OF_DAY);
int mm = now.get(Calendar.MINUTE);
int ss = now.get(Calendar.SECOND);
// 角度:12點鐘方向為 90 度,順時針減少
int sdeg = 90 - ss * 6; // 秒針:60 格,每格 6°
int mdeg = 90 - mm * 6; // 分針:60 格,每格 6°
int hdeg = 90 - hh * 30 - mm/2; // 時針:12 格,每格 30°,加分針微調
// 秒針:細線,每秒重繪
g.setColor(getBackground()); // 擦除舊秒針
g.drawLine(x0, y0, old_X, h - old_Y);
g.setColor(Color.YELLOW);
int x = (int)((r - 8) * Math.cos(RAD * sdeg) + x0);
int y = (int)((r - 8) * Math.sin(RAD * sdeg) + y0) - 2*T0;
g.drawLine(x0, y0, x, h - y);
old_X = x; old_Y = y;
// 分針/時針:粗三角形針,僅角度改變時重繪
if (mdeg != old_M) { line(g, old_M, (int)(r*0.7), getBackground()); old_M = mdeg; }
if (hdeg != old_H) { line(g, old_H, (int)(r*0.5), getBackground()); old_H = hdeg; }
line(g, mdeg, (int)(r*0.7), Color.GREEN); // 分針
line(g, hdeg, (int)(r*0.5), Color.RED); // 時針
void line(Graphics g, int angle, int length, Color c) {
int[] xp = new int[4], yp = new int[4];
xp[0] = x0; yp[0] = y0;
xp[1] = (int)((length-10)*Math.cos(RAD*(angle-4)) + x0);
yp[1] = h - (int)((length-10)*Math.sin(RAD*(angle-4)) + y0);
xp[2] = (int)(length*Math.cos(RAD*angle) + x0);
yp[2] = h - (int)(length*Math.sin(RAD*angle) + y0);
xp[3] = (int)((length-10)*Math.cos(RAD*(angle+4)) + x0);
yp[3] = h - (int)((length-10)*Math.sin(RAD*(angle+4)) + y0);
g.setColor(c);
g.fillPolygon(xp, yp, 4); // 填充三角形針
}
public Clock() {
// ... 視窗初始化 ...
int delay = 1000; // 1 秒
new Timer(delay, e -> repaint()).start(); // 每秒觸發重繪
}
| 技術點 | 實作方式 |
|---|---|
| 即時更新 | javax.swing.Timer 事件分發執行緒安全觸發 repaint() |
| 座標計算 | 三角函數 cos/sin,角度轉弧度 Math.PI/180 |
| 防閃爍 | 背景色擦除舊針 + 僅變化時重繪分/時針 |
| 針樣式 | 秒針:drawLine;分/時針:fillPolygon 三角形 |
| 時間獲取 | Calendar.getInstance() 取得本地時間 |
java.time.LocalTime 替代 Calendar(JDK 8+)JPanel 覆寫 paintComponent() 並啟用 setDoubleBuffered(true) 獲得真正雙重緩衝