Java 我不能启动计时器两次

Java 我不能启动计时器两次,java,swing,timer,Java,Swing,Timer,我正在用Java制作计时器,我需要帮助。主类中添加了一个swing计时器。我有一个jFrame,它有两个面板,一个有jLabel,另一个有3个按钮,“开始”、“停止”和“重置”。当我点击开始,一切正常,当我停止,然后重置。但当我再次单击“开始”时,它会输出以下异常: Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already

我正在用Java制作计时器,我需要帮助。主类中添加了一个swing计时器。我有一个jFrame,它有两个面板,一个有jLabel,另一个有3个按钮,“开始”、“停止”和“重置”。当我点击开始,一切正常,当我停止,然后重置。但当我再次单击“开始”时,它会输出以下异常:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already                                       cancelled.
at java.util.Timer.sched(Unknown Source)
at java.util.Timer.schedule(Unknown Source)
at org.stopwatch.Stopwatch.start(Stopwatch.java:71)
at org.stopwatch.Stopwatch$1.actionPerformed(Stopwatch.java:48)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
这是我的代码: 包org.stopwatch

import static javax.swing.UIManager.getSystemLookAndFeelClassName;
import static javax.swing.UIManager.setLookAndFeel;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Stopwatch {

private static boolean running = false;
public static int time = 0;
public static Timer timer = new Timer();
public static JLabel leftLabel = new JLabel(time + "s");

public static final void main(String[] args) throws Exception {

    setLookAndFeel(getSystemLookAndFeelClassName());
    JFrame f = new JFrame();
    f.setVisible(true);
    f.setSize(1, 1);
    f.setTitle("Секундомір");
    f.setDefaultCloseOperation(3);
    f.setLocationRelativeTo(null);
    JPanel leftPanel = new JPanel();
    f.add(leftPanel, BorderLayout.NORTH);
    leftPanel.add(leftLabel);
    JPanel buttonPanel = new JPanel();
    f.add(buttonPanel, BorderLayout.SOUTH);
    JButton startBtn = new JButton("Start");
    JButton stopBtn = new JButton("Stop");
    JButton resetBtn = new JButton("Reset");
    buttonPanel.add(startBtn);
    buttonPanel.add(stopBtn);
    buttonPanel.add(resetBtn);
    startBtn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent a) {
            running = true;
            start();
        }
    });
    stopBtn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent a) {
            running = false;
            timer.cancel();
        }
    });
    resetBtn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent a) {
            if(!running) {
                time = 0;
                leftLabel.setText("0s");
            }
        }
    });
    f.pack();
}

public static void start() {
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            time++;
            leftLabel.setText(time + "s");
        }
    }, 1000, 1000);
}

}

是的,它的行为完全符合记录。根据:

一旦计时器被终止,它的执行线程将正常终止,并且不能在其上安排更多的任务

并根据
计划的文件
方法:

IllegalStateException
-如果任务已计划或取消,则计时器被取消,或计时器线程终止


基本上,您需要在每个
start
操作上创建一个新的
Timer
,或者不要取消现有的
run
方法,将
TimerTask
run方法更改为在定时器逻辑停止时忽略操作。

答案在错误消息中。它说你不能启动一个被取消的计时器。您必须使用
new
操作符创建一个新的
计时器

start()
函数中执行此操作

timer=新定时器()

如果您决定执行此操作,请不要忘记从声明中删除
new
操作。您将在
start()
函数中覆盖分配

公共静态定时器


如果要存储两次运行之间的时间,则需要在使用新计时器覆盖计时器之前执行此操作。

您应该在
start()
上创建一个新计时器,并用“旧”计时器中的时间填充它

调用timer.cancel()时,请查看

,然后计时器线程将停止! 您可以停止某些任务,但不能停止计时器!当计时器被取消时,你必须重新设置一个tiemr


你可以看看

谢谢。我更新了启动方法中的计时器。现在开始工作了@user2564491为什么要使用
java.util.Timer
?您应该为swing应用程序使用
javax.swing.Timer
,如@peeskillet所示,如果
java.util.Timer
满足他的需求,他肯定应该使用它。如果他需要计时器来更新GUI,那么他应该使用
javax.swing.timer
。但是,情况正好相反-他的GUI正在更新计时器,在这种情况下,没有理由使用swing计时器。@peeskillet您似乎将更新GUI与在GUI中显示计时器混淆了。他的计时器不会触发事件、显示和隐藏元素以及执行其他GUI操作。显示时间与在计时器上触发事件不同。我们很清楚,
setText()
是标签的函数,而不是计时器。如果这还不够清楚,想象一下您希望在GUI中显示一个整数。你会使用一些swing变量吗?