0

I want to create stopwatch that starts after 5 seconds. Without timer it works perfectly, but when I put method startStopwatch() in class Task, that is responsible for executing tasks after time has passed, I get an error. I would be glad for any explanation of what I am doing wrong or if there is a better way to do it. Here is my code.

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

}

Here is an error

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$1(Stopwatch.java:121)
at test.Stopwatch$1.run(Stopwatch.java:117)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(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.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)
Nikolai Shevchenko
  • 7,083
  • 8
  • 33
  • 42

2 Answers2

0

Your Display element is empty when you use the constructor of Stopwatch for the timer. For some reason you create a new stopwatch and don't initialize it. So the Display element which you want to change is null.

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

The constructor should contain initComponents() in order not to have the nullpointer exception. But I'm not sure that it will functionally do what you want.

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

The result of this will be that you won't see an error anymore. But nothing will happen on the original screen either. If you want to see what is happening you need to make it visible. So it should look like this.

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

That makes the new window visible, so a seperate stopwatch. Which might or might not be what you want?

Juru
  • 1,623
  • 17
  • 43
0

The stacktrace shows there is NullPointerException in method displayElapsedTime. This is a one-line method so it shouldn't be that difficult to find the problem. Add debug printing of Display and timerFormat. One of them was not initilsed properly

Sharon Ben Asher
  • 13,849
  • 5
  • 33
  • 47