如何在JFrame中实现点击按钮启动计时器的功能
实现点击按钮启动计时的Java Swing方案
原代码可运行性问题
- 组件初始化顺序错误:未实例化按钮就尝试添加到容器,会触发空指针异常
- 冗余窗口声明:Program类本身继承JFrame,额外定义的JFrame成员变量属于冗余代码
- UI线程阻塞:计时逻辑和
Thread.sleep放在主线程运行,会导致界面无响应 - 绘制逻辑错误:自定义绘制方法调用时机不对,会出现闪屏、重绘后内容消失问题
- 无计时触发控制:程序启动后直接执行计时逻辑,没有和按钮点击事件绑定
完整可运行实现代码
import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.Color; import java.awt.FlowLayout; import javax.swing.*; @SuppressWarnings("serial") public class Program extends JFrame implements ActionListener { private JButton button; private boolean isTimerRunning = false; private int decaseconds = 0; private int seconds = 0; private int minutes = 0; private int hours = 0; public Program() { setLayout(new FlowLayout()); setTitle("计时程序"); setSize(1200,800); setDefaultCloseOperation(EXIT_ON_CLOSE); // 先实例化按钮再添加到容器 button = new JButton("点击开始计时"); button.addActionListener(this); add(button); // 所有组件添加完成后再设置窗口可见 setVisible(true); } @Override public void paint(Graphics g) { super.paint(g); // 仅计时启动后绘制时间文本 if (isTimerRunning) { g.setColor(Color.white); g.fillRect(0, 0, 1200, 800); g.setColor(Color.blue); g.drawString(String.format("%d 小时 : %d 分钟 : %d 秒 : %d 0.01秒", hours, minutes, seconds, decaseconds), 100, 100); } } @Override public void actionPerformed(ActionEvent e) { if (!isTimerRunning) { isTimerRunning = true; button.setText("计时中"); button.setEnabled(false); // 启动独立子线程执行计时逻辑,避免阻塞UI渲染 new Thread(() -> { while (true) { decaseconds++; if(decaseconds == 100) { decaseconds = 0; seconds++; } if(seconds == 60) { seconds = 0; minutes++; } if(minutes == 60) { minutes = 0; hours++; } System.out.printf("%d 小时 : %d 分钟 : %d 秒 : %d 0.01秒%n", hours, minutes, seconds, decaseconds); // 触发界面重绘 repaint(); try { Thread.sleep(10); } catch (InterruptedException ex) { ex.printStackTrace(); } } }).start(); } } public static void main(String[] args) { // Swing界面初始化推荐放在事件调度线程执行,避免线程安全问题 SwingUtilities.invokeLater(Program::new); } }
关键逻辑说明
- 新增
isTimerRunning状态变量控制计时启停,默认关闭,点击按钮后激活 - 修正组件初始化顺序,避免空指针异常,移除冗余的JFrame成员变量
- 计时逻辑放在独立子线程运行,不会卡住界面交互
- 重写
paint方法实现绘制,通过repaint()触发界面更新,避免闪屏 - 按钮点击事件中判断状态,仅首次点击时启动计时,同时禁用按钮防止重复触发
内容的提问来源于stack exchange,提问作者CiY3
相关产品推荐
相关产品推荐

