创建一个以用户输入开始的 java gui 倒数计时器 [英] create a java gui countdown timer that starts with user input

查看:29
本文介绍了创建一个以用户输入开始的 java gui 倒数计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里是 github

解决方案

所以,基本思想是从 Swing Timer 开始.使用它来更新 UI 是安全的,不会阻塞 UI 线程并且可以定期重复.有关详细信息,请参阅如何使用 Swing 计时器.>

因为所有计时器只保证最短持续时间(也就是说,它们可以等待比指定延迟更长的时间),所以您不能仅仅依靠添加预期持续时间来更新状态值.相反,您需要能够计算时间点之间的时间差.

为此,我将使用 Java 8 中引入的日期/时间 API.请参阅 期间和持续时间日期和时间类 了解更多详情.

从那里开始,设置一个Timer,计算从开始时间到现在的Duration并格式化结果

import java.awt.EventQueue;导入 java.awt.GridBagConstraints;导入 java.awt.GridBagLayout;导入 java.awt.Insets;导入 java.awt.event.ActionEvent;导入 java.awt.event.ActionListener;导入 java.time.Duration;导入 java.time.LocalDateTime;导入 javax.swing.JButton;导入 javax.swing.JFrame;导入 javax.swing.JLabel;导入 javax.swing.JPanel;导入 javax.swing.Timer;导入 javax.swing.UIManager;导入 javax.swing.UnsupportedLookAndFeelException;公共类测试{公共静态无效主(字符串 [] args){新测试();}公共测试(){EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){尝试 {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {ex.printStackTrace();}JFrame frame = new JFrame("测试");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.add(new TestPane());框架.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}});}公共类 TestPane 扩展 JPanel {私人本地日期时间开始时间;私人 JLabel 标签;私人定时器定时器;公共测试窗格(){setLayout(new GridBagLayout());GridBagConstraints gbc = new GridBagConstraints();gbc.insets = new Insets(2, 2, 2, 2);gbc.gridwidth = GridBagConstraints.REMAINDER;label = new JLabel("...");添加(标签,gbc);JButton btn = new JButton("开始");btn.addActionListener(new ActionListener() {@覆盖public void actionPerformed(ActionEvent e) {如果(计时器.isRunning()){定时器停止();开始时间 = 空;btn.setText("开始");} 别的 {startTime = LocalDateTime.now();定时器开始();btn.setText("停止");}}});添加(btn,gbc);计时器 = 新计时器(500,新的 ActionListener(){@覆盖public void actionPerformed(ActionEvent e) {LocalDateTime now = LocalDateTime.now();持续时间持续时间 = Duration.between(startTime, now);label.setText(格式(持续时间));}});}受保护的字符串格式(持续时间){长时间 = duration.toHours();long mins = duration.minusHours(hours).toMinutes();long seconds = duration.minusMinutes(mins).toMillis()/1000;return String.format("%02dh %02dm %02ds", hours, mins, seconds);}}}

倒数计时器...

<块引用>

这个计时器开始计时.我如何让它倒计时?我尝试从您的链接中输入代码,但它不起作用.文档也没有帮助我理解太多.

这需要对日期/时间 API 稍有了解.

基本上,您需要知道预期的持续时间(计时器应该运行多长时间)以及计时器已运行的时间.由此,您可以计算出剩余时间(倒计时)

为简单起见,我以 5 分钟的 Duration 开始...

private Duration duration = Duration.ofMinutes(5);

每次Timer打勾,我就简单计算一下运行时间,计算剩余时间...

LocalDateTime now = LocalDateTime.now();Duration runningTime = Duration.between(startTime, now);Duration timeLeft = duration.minus(runningTime);if (timeLeft.isZero() || timeLeft.isNegative()) {timeLeft = Duration.ZERO;//停止计时器并重置 UI}

我真正做的只是玩弄 API.我知道我最终需要一个 Duration (因为这是我正在格式化的)所以我想保留它.由于我还需要一个持续时间"来表示 Timer 应该运行的时间长度,Duration 类似乎是一个不错的起点.>

我曾想我可能需要计算两个 Duration 之间的 差异(就像我为 runningTime 所做的那样),但是作为事实证明,我真正想要的是它们之间的差异(即从另一个中减去一个).

剩下的就是添加一个检查以确保 Timer 不会遇到负时间,并且您知道有一个超时"或倒计时"计时器的概念.

当您处理此类问题时,从可能"如何工作的核心概念"开始总是一件好事 - 即,首先弄清楚您可能如何在几秒钟内倒计时.这为您提供了一些基础工作,从那里,您可以看到 API 提供哪些支持以及如何利用它来发挥您的优势.在这种情况下,Duration 非常简单,并继续提供对输出格式的支持

例如...

import java.awt.EventQueue;导入 java.awt.GridBagConstraints;导入 java.awt.GridBagLayout;导入 java.awt.Insets;导入 java.awt.event.ActionEvent;导入 java.awt.event.ActionListener;导入 java.time.Duration;导入 java.time.LocalDateTime;导入 javax.swing.JButton;导入 javax.swing.JFrame;导入 javax.swing.JLabel;导入 javax.swing.JPanel;导入 javax.swing.Timer;导入 javax.swing.UIManager;导入 javax.swing.UnsupportedLookAndFeelException;公共类测试{公共静态无效主(字符串 [] args){新测试();}公共测试(){EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){尝试 {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {ex.printStackTrace();}JFrame frame = new JFrame("测试");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.add(new TestPane());框架.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}});}公共类 TestPane 扩展 JPanel {私人本地日期时间开始时间;私人 JLabel 标签;私人定时器定时器;私人持续时间 = Duration.ofMinutes(5);公共测试窗格(){setLayout(new GridBagLayout());GridBagConstraints gbc = new GridBagConstraints();gbc.insets = new Insets(2, 2, 2, 2);gbc.gridwidth = GridBagConstraints.REMAINDER;label = new JLabel("...");添加(标签,gbc);JButton btn = new JButton("开始");btn.addActionListener(new ActionListener() {@覆盖public void actionPerformed(ActionEvent e) {如果(计时器.isRunning()){定时器停止();开始时间 = 空;btn.setText("开始");} 别的 {startTime = LocalDateTime.now();定时器开始();btn.setText("停止");}}});添加(btn,gbc);计时器 = 新计时器(500,新 ActionListener(){@覆盖public void actionPerformed(ActionEvent e) {LocalDateTime now = LocalDateTime.now();Duration runningTime = Duration.between(startTime, now);Duration timeLeft = duration.minus(runningTime);if (timeLeft.isZero() || timeLeft.isNegative()) {timeLeft = Duration.ZERO;btn.doClick();//欺骗}label.setText(format(timeLeft));}});}受保护的字符串格式(持续时间){长时间 = duration.toHours();long mins = duration.minusHours(hours).toMinutes();long seconds = duration.minusMinutes(mins).toMillis()/1000;return String.format("%02dh %02dm %02ds", hours, mins, seconds);}}}

Here is the github link

So I was trying to create an application and broke it down into 3 parts, one of which is to create a timer. This timer has two fields: one to input minutes and one to input seconds. It is supposed to take in minutes or seconds typed in by the user and display a countdown on the application screen. When the timer reaches 0, it alerts the user. I have searched everywhere and could not find a countdown timer in Java that does that. All I found were countdown timers that work in console or countdown timers that already have predefined values set by the developer, not user.

I wanted to make a timer just like this one from google: Google Timer

P.s. I am a new self-taught programmer. This is my second java project so I don't have much experience yet. Looking forward to any help :)

Here is my code:

public class TestPane extends JFrame {

private LocalDateTime startTime;
private JLabel timerLabel;
private Timer timer;
private JButton startbtn;
private JTextField timeSet;
int count;
int count_2;
private Duration duration;
private JTextField minSet;
private JTextField secSet;


public TestPane() {


    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
    setSize(400,400);
    getContentPane().setLayout(new CardLayout(0, 0));

    JPanel panel = new JPanel();
    getContentPane().add(panel, "name_87856346254020");
    panel.setLayout(null);

    timerLabel = new JLabel("New label");
    timerLabel.setBounds(59, 48, 194, 14);
    panel.add(timerLabel);

    startbtn = new JButton("New button");
    startbtn.setBounds(124, 187, 89, 23);
    panel.add(startbtn);

    timeSet = new JTextField(1);
    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(60);
    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);


    startbtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                 startbtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                timeSet.getText().trim();
                if(timeSet.getText().isEmpty()) {
                    duration = Duration.ofMinutes(count_min);
                } else {
                count_hour = Integer.parseInt(timeSet.getText());                   
                duration = Duration.ofHours(count_hour);                
                }

                minSet.getText().trim();                                
                if(minSet.getText().isEmpty()) {
                    duration = Duration.ofHours(count_hour);
                } else {
                    count_min = Integer.parseInt(minSet.getText());
                    duration = Duration.ofMinutes(count_min);                   
                }

                secSet.getText().trim();
                if(secSet.getText().isEmpty() && minSet.getText().isEmpty()) {
                duration = Duration.ofHours(count_hour);        
                } 
                else if(secSet.getText().isEmpty() && timeSet.getText().isEmpty()){
                    duration = Duration.ofMinutes(count_sec);
                }
                else {                  
                    count_sec = Integer.parseInt(secSet.getText());
                    duration = duration.ofSeconds(count_sec);
                }


                if (timer.isRunning()) {
                    timer.stop();
                    startTime = null;
                    startbtn.setText("Start");
                } 
                else {
                    startTime = LocalDateTime.now();
                    timer.start();
                    startbtn.setText("Stop");
                }

            }
        });           

        timer = new Timer(500, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                LocalDateTime now = LocalDateTime.now();
                Duration runningTime = Duration.between(startTime, now);
                Duration timeLeft = duration.minus(runningTime);
                if (timeLeft.isZero() || timeLeft.isNegative()) {
                    timeLeft = Duration.ZERO;
                    startbtn.doClick(); // Cheat
                }

                timerLabel.setText(format(timeLeft));
            }
        });
    }

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


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

Update: So far, when the user sets hours and leaves minutes and seconds blank, it counts down from hours. Same with seconds. However, I cannot get the minutes to do the same. If I leave everything blank except for minutes, the timer does nothing. Also, I want to make the timer work simultaneously with hours, minutes and seconds. As of now, it only works with one unit at a time.

解决方案

So, the basic idea is to start with a Swing Timer. It's safe to use it to update the UI, won't block the UI thread and can repeat at a regular interval. See How to use Swing Timers for more details.

Because all timers only guarantee a minimum duration (that is, they could wait longer then the specified delay), you can't rely on updating a state value simply by adding the expected duration. Instead, you need to be able to calculate the difference in time between to points in time.

For this, I would use the Date/Time API introduced in Java 8. See Period and Duration and Date and Time Classes for more details.

From there, it's a simple matter of setting up a Timer, calculating the Duration from the start time to now and formatting the result

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private LocalDateTime startTime;
        private JLabel label;
        private Timer timer;

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            label = new JLabel("...");
            add(label, gbc);

            JButton btn = new JButton("Start");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (timer.isRunning()) {
                        timer.stop();
                        startTime = null;
                        btn.setText("Start");
                    } else {
                        startTime = LocalDateTime.now();
                        timer.start();
                        btn.setText("Stop");
                    }
                }
            });
            add(btn, gbc);

            timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    LocalDateTime now = LocalDateTime.now();
                    Duration duration = Duration.between(startTime, now);
                    label.setText(format(duration));
                }
            });
        }

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

    }


}

Countdown timer...

This timer counts up. How would I get it to count down instead? I tried putting in code from your links but it wouldn't work. The documentations didn't help me understand much either.

This requires a slightly better understanding of the Date/Time API.

Basically, you need to know the expected duration (how long the timer should run for) and the amount of time the timer has been running. From this, you can calculate the amount of time remaining (the countdown)

For simplicity, I started with a Duration of 5 minutes...

private Duration duration = Duration.ofMinutes(5);

Each time the Timer ticked, I simply calculated the running time and calculate the remaining time...

LocalDateTime now = LocalDateTime.now();
Duration runningTime = Duration.between(startTime, now);
Duration timeLeft = duration.minus(runningTime);
if (timeLeft.isZero() || timeLeft.isNegative()) {
    timeLeft = Duration.ZERO;
    // Stop the timer and reset the UI
}

All I really did was played around with the API. I knew I would need a Duration in the end (as that's what I was formatting) so I wanted to keep that. Since I also needed a "duration" of time, to represent the length of time the Timer should run for, the Duration class seemed like a good place to start.

I had thought I might need to calculate the difference between the two Durations (like I did for the runningTime), but as it turns out, all I really wanted was the difference between them (ie subtraction of one from the other).

All that was left was to add a check to ensure that the Timer doesn't run into negative time and you know have a concept of a "time out" or "count down" timer.

When you're dealing with these kinds of problems, its always a good thing to start out with a "core concept" of how it "might" work - ie, start by figuring out how you might count down in seconds. This gives you some ground work, from there, you can see what support the API provides and how you might use it to your advantage. In this case, Duration was super easy and continued to provide support for the formatting of the output

For example...

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private LocalDateTime startTime;
        private JLabel label;
        private Timer timer;

        private Duration duration = Duration.ofMinutes(5);

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            label = new JLabel("...");
            add(label, gbc);

            JButton btn = new JButton("Start");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (timer.isRunning()) {
                        timer.stop();
                        startTime = null;
                        btn.setText("Start");
                    } else {
                        startTime = LocalDateTime.now();
                        timer.start();
                        btn.setText("Stop");
                    }
                }
            });
            add(btn, gbc);

            timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    LocalDateTime now = LocalDateTime.now();
                    Duration runningTime = Duration.between(startTime, now);
                    Duration timeLeft = duration.minus(runningTime);
                    if (timeLeft.isZero() || timeLeft.isNegative()) {
                        timeLeft = Duration.ZERO;
                        btn.doClick(); // Cheat
                    }

                    label.setText(format(timeLeft));
                }
            });
        }

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

    }

}

这篇关于创建一个以用户输入开始的 java gui 倒数计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆