Java Swing 计时器倒计时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28337718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 13:24:52  来源:igfitidea点击:

Java Swing Timer Countdown

javaswingtimer

提问by BigBigBiggle

I have to make a countdown program which also shows the tenths of a second; for example from a 10.0 second countdown, it should display 9.9s, 9.8s, ... 0.0s

我必须制作一个倒计时程序,它也显示十分之一秒;例如从 10.0 秒倒计时,它应该显示 9.9s, 9.8s, ... 0.0s

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         

        timer.start();
        timer2.start();

}                                        


Double timeLeft=5000; //5 seconds
Timer timer=new Timer(1,countDown);
Timer timer2=new Timer(1000,countDown2);
ActionListener countDown=new ActionListener()
{
    public void actionPerformed(ActionEvent e)
    {
        timeLeft--;
        SimpleDateFormat df=new SimpleDateFormat("mm:ss:S");
        jLabel1.setText(df.format(timeLeft));
        if(timeLeft<=0)
        {
            timer.stop();
        }
    }
};

what happens is it's taking more than 5 seconds to finish the 5 seconds.

发生的事情是完成这 5 秒需要超过 5 秒。

I compared the code above with another Timer

我将上面的代码与另一个计时器进行了比较

int timeLeft2=5;

ActionListener countDown2=new ActionListener()
{
    public void actionPerformed(ActionEvent e)
    {
        timeLeft2--;

        jLabel2.setText(String.valueOf(timeLeft2));
        if(timeLeft2<=0)
        {
            time2.stop();
        }                  
    }
};

is it natural that they don't get the same?

他们不一样是自然的吗?

回答by MadProgrammer

The time between ticks (the time when actionPerfomedis called) is variable, it only guarantees that it will be at least nmilliseconds

滴答之间的时间(actionPerfomed被调用的时间)是可变的,它只保证至少是n毫秒

Instead of relying on some counter, which could become unreliable over time, you should try and calculate the difference between the time the Timerwas started and the current time, for example...

您应该尝试计算Timer开始时间和当前时间之间的差异,而不是依赖某些可能会随着时间的推移变得不可靠的计数器,例如......

CountDown

倒数

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.SimpleDateFormat;
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 CountDown {

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

    public CountDown() {
        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 Timer timer;
        private long startTime = -1;
        private long duration = 5000;

        private JLabel label;

        public TestPane() {
            setLayout(new GridBagLayout());
            timer = new Timer(10, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (startTime < 0) {
                        startTime = System.currentTimeMillis();
                    }
                    long now = System.currentTimeMillis();
                    long clockTime = now - startTime;
                    if (clockTime >= duration) {
                        clockTime = duration;
                        timer.stop();
                    }
                    SimpleDateFormat df = new SimpleDateFormat("mm:ss:SSS");
                    label.setText(df.format(duration - clockTime));
                }
            });
            timer.setInitialDelay(0);
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (!timer.isRunning()) {
                        startTime = -1;
                        timer.start();
                    }
                }
            });
            label = new JLabel("...");
            add(label);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}

回答by Adrian Leonhard

Updating the label probably takes more that 1ms, which is why it can't keep up. If you only need to display tenths of a second, simply have your timer update less often.

更新标签可能需要超过 1 毫秒,这就是它无法跟上的原因。如果您只需要显示十分之一秒,只需减少您的计时器更新频率即可。

ActionListener countDown=new ActionListener()
{
    public void actionPerformed(ActionEvent e)
    {
        timeLeft -= 100;
        SimpleDateFormat df=new SimpleDateFormat("mm:ss:S");
        jLabel1.setText(df.format(timeLeft));
        if(timeLeft<=0)
        {
            timer.stop();
        }
    }
};
Timer timer=new Timer(100, countdown);