Java 带计时器的秒表

Java stopwatch with timer

我想创建 5 秒后启动的秒表。没有计时器,它工作得很好,但是当我把方法 startStopwatch() 放在 class 任务中时,它负责在时间过去后执行任务,我得到一个错误。我很乐意解释我做错了什么,或者是否有更好的方法。 这是我的代码。

import java.lang.reflect.InvocationTargetException;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.SwingUtilities;


public class Stopwatch extends javax.swing.JFrame implements Runnable{

private javax.swing.JLabel Display;
private javax.swing.JButton StartButton;
private javax.swing.JButton StopButton;

private final static java.text.SimpleDateFormat timerFormat = new java.text.SimpleDateFormat("mm : ss.SSS");
private long elapsed;
private long startTime;
private Thread updater;
private boolean isRunning= false;
private Timer timer;

public Stopwatch() {
    initComponents();
}

private void initComponents() {

    Display = new javax.swing.JLabel();
    StartButton = new javax.swing.JButton();
    StopButton = new javax.swing.JButton();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    Display.setText("00 : 00.000");

    StartButton.setText("Start");
    StartButton.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            StartButtonActionPerformed(evt);
        }
    });

    StopButton.setText("Stop");
    StopButton.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            StopButtonActionPerformed(evt);
        }
    });

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addGap(131, 131, 131)
                    .addComponent(StartButton)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                    .addComponent(StopButton))
                .addGroup(layout.createSequentialGroup()
                    .addGap(165, 165, 165)
                    .addComponent(Display)))
            .addContainerGap(147, Short.MAX_VALUE))
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(124, 124, 124)
            .addComponent(Display)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(StartButton)
                .addComponent(StopButton))
            .addContainerGap(133, Short.MAX_VALUE))
    );

    pack();
    setLocationRelativeTo(null);
}                    

private void StopButtonActionPerformed(java.awt.event.ActionEvent evt) {                                           
    stopStopwatch();
}                                          

private void StartButtonActionPerformed(java.awt.event.ActionEvent evt) {                                            
    //startStopwatch();
    new Stopwatch(5);
}                                           

public static void main(String args[]) {

    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new Stopwatch().setVisible(true);
        }
    });
}

//STOPWATCH
@Override
public void run() {
    try{
        while(isRunning){
            SwingUtilities.invokeAndWait(displayUpdater);
            Thread.sleep(10);
        }
    }catch(InterruptedException e){
        e.printStackTrace();
    } catch (InvocationTargetException ex) {
        ex.printStackTrace();
    }
}

private final Runnable displayUpdater= new Runnable() {
    public void run(){
        displayElapsedTime(System.currentTimeMillis() - Stopwatch.this.startTime);
    }
};

private void displayElapsedTime (long elapsedTime1){
    Display.setText(timerFormat.format(new java.util.Date(elapsedTime1)));
}
public void startStopwatch(){
    System.out.println("2:Start stopwatch."); 
    startTime=  System.currentTimeMillis();
    isRunning = true;
    updater = new Thread(this);
    updater.start();
}
private void stopStopwatch(){
    System.out.println("3:Stop stopwatch.");
    elapsed =  System.currentTimeMillis() - startTime;
    isRunning= false;
    try{
        updater.join();
    }catch(InterruptedException ie){
        ie.printStackTrace();
    }
    displayElapsedTime(elapsed);
}

//TIMER
public Stopwatch(int seconds){
    timer = new Timer();
    timer.schedule(new Task(), seconds * 1000);
}

class Task extends TimerTask{
    @Override
    public void run() {
        System.out.println("1:Timer has finished.");
        timer.cancel();
        startStopwatch();
    }
}

}

这里有一个错误

java.lang.reflect.InvocationTargetException
at java.awt.EventQueue.invokeAndWait(Unknown Source)
at java.awt.EventQueue.invokeAndWait(Unknown Source)
at javax.swing.SwingUtilities.invokeAndWait(Unknown Source)
at test.Stopwatch.run(Stopwatch.java:105)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at test.Stopwatch.displayElapsedTime(Stopwatch.java:122)
at test.Stopwatch.access(Stopwatch.java:121)
at test.Stopwatch.run(Stopwatch.java:117)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access0(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.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)

当您为计时器使用 Stopwatch 的构造函数时,您的 Display 元素为空。出于某种原因,您创建了一个新的秒表并且没有对其进行初始化。因此,您要更改的 Display 元素为空。

//TIMER
public StopWatch(int seconds) {
    timer = new Timer();
    timer.schedule(new Task(), seconds * 1000);
}

构造函数应包含 initComponents() 以避免空指针异常。但我不确定它是否会在功能上做你想做的事。

//TIMER
public StopWatch(int seconds) {
    initComponents();
    timer = new Timer();
    timer.schedule(new Task(), seconds * 1000);
}

这样做的结果是您不会再看到错误。但在原始屏幕上也不会发生任何事情。如果你想看到正在发生的事情,你需要让它可见。所以它应该是这样的。

//TIMER
public StopWatch(int seconds) {
    initComponents();
    setVisible(true);
    timer = new Timer();
    timer.schedule(new Task(), seconds * 1000);
}

这使得新的 window 可见,因此是一个单独的秒表。哪个可能是您想要的,也可能不是?

堆栈跟踪显示方法 displayElapsedTime 中存在 NullPointerException。 这是一种单线方法,因此找到问题应该不难。添加 Display 和 timerFormat 的调试打印。其中之一未正确初始化