tags:

views:

192

answers:

2
+2  Q: 

Stop a stopwatch

I have the following code in a JPanel class which is added to a another class (JFrame). What I'm trying to implement is some sort of a stopwatch program.

startBtn.addActionListener(new startListener());

class startListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        Timer time = new Timer();
        time.scheduleAtFixedRate(new Stopwatch(), 1000, 1000);
    }
}

This is another class which basically the task.

public class Stopwatch extends TimerTask {

    private final double start = System.currentTimeMillis();

    public void run() {
        double curr = System.currentTimeMillis();
        System.out.println((curr - start) / 1000);
    }
}

The timer works fine and this is definitely far from complete but I'm not sure how to code the stop button which should stop the timer. Any advice on this? BTW I'm using java.util.timer

EDIT: I want to be able to start it again after stopping it (without the timer being reset)

+2  A: 

You can either cancel the entire Timer by calling Timer.cancel(), or you can cancel individual tasks by calling TimerTask.cancel().

Either way, you'll need to keep a reference to the timer and/or task instance when you create it, so that your stop routine can call the appropriate cancel method.

Update:

So you effectively want to be able to pause the timer? I don't think this is supported by the standard interface in java.util.Timer. You could do this by adding a pause() method (or similar) to your custom task, recording the elapsed time up to that point, and restarting the counting when the start button is clicked again. Note that using this technique, you wouldn't stop the timer task itself until you're finished with it completely. It still runs in the background, but you only do anything with it when the stopwatch has been started and is "running" (ie. some kind of flag to indicate the stopwatch's state).

A couple of notes:

  • java.util.Timer runs on a non-EDT thread, so if you're interacting with member variables in both the timer and in Swing action events, you'll need to appropriately handle the implications of multiple threads. It might be worth investigating javax.swing.Timer, which will fire events on the EDT.

  • Also, if you want a super-duper accurate stopwatch, you might consider using System.nanoTime() rather than currentTimeMillis().

Ash
Sorry, this isn't exactly what I was looking for. I edited my question.
James Morgan
+1  A: 

If javax.swing.Timer is an acceptable alternative, as @Ash suggests, here is an example.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

public class JTimeLabel extends JLabel implements ActionListener {

    private static final String Start = "Start";
    private static final String Stop = "Stop";
    private DecimalFormat df = new DecimalFormat("000.0");
    private Timer timer = new javax.swing.Timer(100, this);
    private long now = System.currentTimeMillis();

    public JTimeLabel() {
        this.setHorizontalAlignment(JLabel.CENTER);
        this.setText(when());
    }

    public void actionPerformed(ActionEvent ae) {
        setText(when());
    }

    public void start() {
        timer.start();
    }

    public void stop() {
        timer.stop();
    }

    private String when() {
        return df.format((System.currentTimeMillis() - now) / 1000d);
    }

    private static void create() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JTimeLabel jtl = new JTimeLabel();
        jtl.setFont(new Font("Dialog", Font.BOLD, 32));
        f.add(jtl, BorderLayout.CENTER);

        final JButton button = new JButton("Stop");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String cmd = e.getActionCommand();
                if (Stop.equals(cmd)) {
                    jtl.stop();
                    button.setText(Start);
                } else {
                    jtl.start();
                    button.setText(Stop);
                }

            }
        });
        f.add(button, BorderLayout.SOUTH);
        f.pack();
        f.setVisible(true);
        jtl.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                create();
            }
        });
    }
}
trashgod