You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:Java GUI用户自定义倒计时计时器开发问题

Fixing Your Java GUI Countdown Timer Issues

Hey there! Let's work through the problems you're facing with your countdown timer. I've looked over your code and spotted a few key issues that are causing the bugs you mentioned. Let's break them down and fix them one by one.

Key Issues in Your Current Code

  • Nested ActionListener on Start Button: You added an ActionListener inside another ActionListener for the start button. That means the first click only registers the second listener, and the timer logic won't run until the second click—this is why some inputs seem unresponsive.
  • Broken Duration Calculation: Right now, you're overwriting the duration variable each time you check a time field, instead of adding up hours, minutes, and seconds together. For example, if you enter both hours and minutes, the minutes will overwrite the hours value entirely. Also, variables like count_hour, count_min, and count_sec aren't declared anywhere, which would cause compilation errors.
  • Timer Initialization Timing: The Timer is initialized inside the first button click listener, so when you first click "Start", timer is null and calling timer.isRunning() would throw a NullPointerException.

Fixed Code with Combined Time Support

Here's the revised code that fixes all these issues and lets you combine hours, minutes, and seconds:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;

public class TestPane extends JFrame {
    private LocalDateTime startTime;
    private JLabel timerLabel;
    private Timer timer;
    private JButton startbtn;
    private JTextField timeSet;
    private JTextField minSet;
    private JTextField secSet;

    public TestPane() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(400, 400);
        getContentPane().setLayout(new CardLayout(0, 0));
        
        JPanel panel = new JPanel();
        getContentPane().add(panel, "name_87856346254020");
        panel.setLayout(null);
        
        timerLabel = new JLabel("00h 00m 00s");
        timerLabel.setBounds(59, 48, 194, 14);
        panel.add(timerLabel);
        
        startbtn = new JButton("Start");
        startbtn.setBounds(124, 187, 89, 23);
        panel.add(startbtn);
        
        timeSet = new JTextField();
        timeSet.setBounds(106, 85, 86, 20);
        panel.add(timeSet);
        timeSet.setColumns(10);
        
        JLabel lblHours = new JLabel("Hours");
        lblHours.setBounds(29, 88, 46, 14);
        panel.add(lblHours);
        
        JLabel lblMinss = new JLabel("Mins");
        lblMinss.setBounds(29, 114, 46, 14);
        panel.add(lblMinss);
        
        JLabel lblSecs = new JLabel("Secs");
        lblSecs.setBounds(29, 139, 46, 14);
        panel.add(lblSecs);
        
        minSet = new JTextField();
        minSet.setBounds(75, 116, 86, 20);
        panel.add(minSet);
        minSet.setColumns(10);
        
        secSet = new JTextField();
        secSet.setBounds(75, 147, 86, 20);
        panel.add(secSet);
        secSet.setColumns(10);
        
        // Initialize timer here instead of inside the button listener
        timer = new Timer(1000, new ActionListener() { // Use 1000ms (1 second) for smoother updates
            @Override
            public void actionPerformed(ActionEvent e) {
                LocalDateTime now = LocalDateTime.now();
                Duration runningTime = Duration.between(startTime, now);
                Duration totalDuration = getTotalDuration();
                Duration timeLeft = totalDuration.minus(runningTime);
                
                if (timeLeft.isZero() || timeLeft.isNegative()) {
                    timeLeft = Duration.ZERO;
                    timer.stop();
                    startbtn.setText("Start");
                    JOptionPane.showMessageDialog(null, "Time's up!"); // Add end reminder
                }
                
                timerLabel.setText(format(timeLeft));
            }
        });
        
        // Single ActionListener for the start button
        startbtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (timer.isRunning()) {
                    timer.stop();
                    startbtn.setText("Start");
                } else {
                    startTime = LocalDateTime.now();
                    timer.start();
                    startbtn.setText("Stop");
                }
            }
        });
        
        setVisible(true); // Move this to the end so all components are initialized first
    }

    // Calculate total duration by adding hours, minutes, seconds together
    private Duration getTotalDuration() {
        long hours = parseInput(timeSet.getText(), 0);
        long mins = parseInput(minSet.getText(), 0);
        long secs = parseInput(secSet.getText(), 0);
        
        return Duration.ofHours(hours)
                .plusMinutes(mins)
                .plusSeconds(secs);
    }

    // Helper method to safely parse text inputs to numbers
    private long parseInput(String input, long defaultValue) {
        try {
            return Long.parseLong(input.trim());
        } catch (NumberFormatException ex) {
            return defaultValue; // Return 0 if input is empty or invalid
        }
    }

    protected String format(Duration duration) {
        long hours = duration.toHours();
        long mins = duration.minusHours(hours).toMinutes();
        long seconds = duration.minusHours(hours).minusMinutes(mins).getSeconds();
        
        return String.format("%02dh %02dm %02ds", hours, mins, seconds);
    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(() -> new TestPane()); // Use SwingUtilities for thread safety
    }
}

What Changed & Why

  1. Removed Nested ActionListener: Now there's only one listener on the start button, so clicking it immediately toggles the timer state.
  2. Combined Duration Calculation: The new getTotalDuration() method adds up hours, minutes, and seconds from all three fields instead of overwriting the duration. Empty or invalid inputs default to 0.
  3. Early Timer Initialization: The Timer is created when the frame initializes, so no more null pointer errors when checking if it's running.
  4. Added Time's Up Reminder: A JOptionPane pops up when the countdown finishes, as per your requirement.
  5. Thread-Safe Initialization: Used SwingUtilities.invokeLater() in main to ensure Swing components are created on the Event Dispatch Thread (best practice for Swing apps).
  6. Smoother Updates: Changed the timer interval to 1000ms (1 second) so the display updates once per second, which is more intuitive for a countdown.

How to Use It

  • Enter any combination of hours, minutes, and seconds (leave fields empty if you don't need that unit).
  • Click "Start" to begin the countdown; click "Stop" to pause it.
  • When the timer reaches 0, a popup will notify you that time's up.

内容的提问来源于stack exchange,提问作者Syed Sadman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:51:39