構建一個可啟動/停止、獨立運行的數字時鐘,核心需求:
import java.awt.*;
import java.awt.event.*;
import java.util.Date;
class Clock extends Label implements Runnable {
private Thread clockThread;
public Clock() { setText(new Date().toString()); }
public synchronized void start() {
if (clockThread == null) {
clockThread = new Thread(this);
clockThread.start();
}
}
public synchronized void stop() { clockThread = null; }
@Override
public void run() {
Thread current = Thread.currentThread();
while (clockThread == current) { // 線程身份校驗
setText(new Date().toString());
try { Thread.sleep(1000); }
catch (InterruptedException e) { break; }
}
}
}
public class ClockFrame extends Frame implements ActionListener {
private Button startBtn = new Button("Start");
private Button stopBtn = new Button("Stop");
private Clock clock = new Clock();
public ClockFrame() {
super("數字時鐘");
setLayout(new FlowLayout());
add(startBtn); startBtn.addActionListener(this);
add(stopBtn); stopBtn.addActionListener(this);
add(clock);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
pack(); setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == startBtn) clock.start();
else if (e.getSource() == stopBtn) clock.stop();
}
public static void main(String[] args) { new ClockFrame(); }
}
優點:邏輯清晰,展示線程生命週期管理;缺點:AWT 組件已過時,Label 不支持豐富樣式。
import javax.swing.*;
import java.awt.*;
import java.util.Date;
public class TimeDemo extends JFrame implements Runnable {
private Thread clockThread;
public TimeDemo() {
super("Swing 數字時鐘");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setFont(new Font("Times New Roman", Font.BOLD, 60));
setBounds(400, 300, 300, 100);
setVisible(true);
startClock();
}
private synchronized void startClock() {
if (clockThread == null) {
clockThread = new Thread(this);
clockThread.start();
}
}
@Override
public void run() {
while (clockThread != null) {
repaint(); // 觸發 paint()
try { Thread.sleep(1000); }
catch (InterruptedException e) { break; }
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
Date now = new Date();
String time = String.format("%tH:%tM:%tS", now, now, now);
g.setColor(Color.GREEN);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.drawString(time, 20, 80);
}
public static void main(String[] args) { new TimeDemo(); }
}
關鍵點:
paint() 自定義繪製,避免標籤組件限制repaint() 異步調度繪製,不阻塞事件線程EXIT_ON_CLOSE 確保程序正常退出import java.awt.*;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.*;
class ClockCanvas extends Canvas implements Runnable {
private Thread thread;
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
public ClockCanvas() {
thread = new Thread(this);
thread.start();
}
@Override
public void run() {
while (true) {
repaint();
try { Thread.sleep(1000); }
catch (InterruptedException e) { break; }
}
}
@Override
public void paint(Graphics g) {
g.setFont(new Font("宋體", Font.BOLD, 16));
g.setColor(Color.ORANGE);
g.drawString(sdf.format(Calendar.getInstance().getTime()), 45, 25);
}
}
public class ClockApp {
public static void main(String[] args) {
JFrame frame = new JFrame("Canvas 時鐘");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ClockCanvas());
frame.setSize(300, 150);
frame.setVisible(true);
}
}
優勢:
SimpleDateFormat 靈活格式化(含中文單位)Calendar 替代過時的 Date.getHours() 等方法| 維度 | 建議 |
|---|---|
| UI 框架 | 優先 Swing (JFrame/JPanel),避免 AWT |
| 時間獲取 | 使用 Calendar.getInstance() 或 Java 8 LocalDateTime.now() |
| 格式化 | DateTimeFormatter (Java 8+) 線程安全,優於 SimpleDateFormat |
| 線程控制 | volatile 標誌位 + interrupt(),避免直接比較 Thread 引用 |
| 繪製方式 | 覆寫 paintComponent(Graphics) (Swing) 而非 paint() |
| 資源釋放 | 窗口關閉時調用 interrupt() 並 join() 等待線程結束 |