【问题标题】:create a java gui countdown timer that starts with user input创建一个从用户输入开始的 java gui 倒数计时器
【发布时间】:2018-01-01 00:36:21
【问题描述】:

这里是githublink

所以我试图创建一个应用程序并将其分解为 3 个部分,其中之一是创建一个计时器。这个计时器有两个字段:一个输入分钟,一个输入秒。它应该在几分钟或几秒钟内由用户输入并在应用程序屏幕上显示倒计时。当计时器达到 0 时,它会提醒用户。我到处搜索,在 Java 中找不到这样做的倒数计时器。我发现的只是在控制台中工作的倒数计时器或已经具有由开发人员而不是用户设置的预定义值的倒数计时器。

我想制作一个类似 google 的计时器: Google Timer

附:我是一个新的自学程序员。这是我的第二个 java 项目,所以我还没有太多经验。期待任何帮助:)

这是我的代码:

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();
    }
}

更新: 到目前为止,当用户设置小时并将分钟和秒留空时,它会从小时开始倒计时。与秒相同。但是,我无法获得时间来做同样的事情。如果我把所有东西都留空,除了分钟,计时器什么也不做。另外,我想让计时器与小时、分钟和秒同时工作。截至目前,它一次只能与一个单元一起使用。

【问题讨论】:

  • 你可以颠倒这个概念,所以你有一个开始时间和一个持续时间,让Timer定期打勾,比如说半秒,然后检查计时器是否已经运行在指定期间。您可以通过从持续时间中减去运行时间来轻松生成倒计时时间
  • 作为example - 请记住,大多数时间操作发生在毫秒级别,因此您需要将输入转换为毫秒。您可能还想看看How to use Swing Timers
  • 添加一个稍微复杂一点的example
  • 谢谢,我会查看链接。这是我在 Java 中的第二个项目,所以我想我需要从小处着手。
  • 这个Duration.ofHours(count);什么都不做

标签: java swing timer


【解决方案1】:

因此,基本思想是从 Swing Timer 开始。使用它来更新 UI 是安全的,不会阻塞 UI 线程并且可以定期重复。详情请见How to use Swing Timers

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

为此,我将使用 Java 8 中引入的日期/时间 API。有关详细信息,请参阅 Period and DurationDate and Time Classes

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

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);
        }

    }


}

倒计时...

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

这需要对日期/时间 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;
    // Stop the timer and reset the UI
}

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

我原以为我可能需要计算 between 和两个 Durations 的差异(就像我为 runningTime 所做的那样),但事实证明,我真正想要的只是它们之间的差异(即一个相减)。

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

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

例如...

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);
        }

    }

}

【讨论】:

  • 感谢您让我开始!我需要获取用户输入并从用户在 JTextField 中指定的内容开始倒计时。我只是不知道该怎么做。
  • 我建议当启动按钮被触发时,您在该点从文本字段中读取值
  • 这个计时器开始计时。我该如何让它倒计时呢?我尝试从您的链接中输入代码,但它不起作用。这些文档也没有帮助我理解太多。
  • 你需要 - 一个持续时间(计时器应该运行多长时间);计时器的当前运行时间(你已经有了);然后,您只需要计算两者之间的差异。例如thisthis 之类的东西
  • 非常感谢您的帮助!我遇到了小时和秒的问题。我发现如果我设置小时,计时器将使用秒而不是小时来倒计时。但是,我可以通过添加以下内容来解决该问题: long seconds = (duration.minusMinutes(mins).toMillis() / 1000) %60;
猜你喜欢
  • 2023-01-10
  • 1970-01-01
  • 1970-01-01
  • 2015-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多