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.
st
long startTime = System.currentTimeMillis();
Timer timer = new Timer(100,new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
long elapsedTime = System.currentTimeMillis()-startTime;
long mil = elapsedTime%1000;
long sec = elapsedTime/1000%60;
long min = elapsedTime/60000%60;
long hr = elapsedTime/3600000;
label.setText(String.format("%02d:%02d:%02d.%03d", hr,min,sec,mil));
}
});
timer.start();
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()
.
I changed the trashgod's source.
update:
public class StopWatch extends JLabel implements ActionListener {
private static final String Start = "Start";
private static final String Pause = "Pause";
private static final String Reset = "Reset";
private boolean isRunning;
private Timer timer = new javax.swing.Timer(100, this);
private long initTime = System.currentTimeMillis();
private long startTime;
private long pauseTime;
public StopWatch() {
this.setHorizontalAlignment(JLabel.CENTER);
this.setText(getCurrentTime(System.currentTimeMillis() - initTime));
}
public void actionPerformed(ActionEvent ae) {
setText(getCurrentTime(System.currentTimeMillis() - startTime));
}
public void start() {
if (isRunning == false) {
startTime = System.currentTimeMillis();
} else {
startTime = System.currentTimeMillis() - (pauseTime - startTime);
}
isRunning = true;
timer.start();
}
public void pause() {
pauseTime = System.currentTimeMillis();
timer.stop();
}
public void reset() {
startTime = 0;
isRunning = false;
this.setText(getCurrentTime(System.currentTimeMillis() - System.currentTimeMillis()));
}
private String getCurrentTime(long time) {
return myFormat(time);
}
private String myFormat(final long time) {
final long hr = TimeUnit.MILLISECONDS.toHours(time);
final long min = TimeUnit.MILLISECONDS.toMinutes(time
- TimeUnit.HOURS.toMillis(hr));
final long sec = TimeUnit.MILLISECONDS.toSeconds(time
- TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
final long ms = TimeUnit.MILLISECONDS.toMillis(time
- TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min)
- TimeUnit.SECONDS.toMillis(sec));
return String.format("%02d:%02d:%02d.%01d", hr, min, sec, ms/100);
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final StopWatch textLabel = new StopWatch();
textLabel.setFont(new Font("Dialog", Font.BOLD, 32));
f.add(textLabel, BorderLayout.CENTER);
final JButton button = new JButton(Start);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (Pause.equals(cmd)) {
textLabel.pause();
button.setText(Start);
} else {
textLabel.start();
button.setText(Pause);
}
}
});
final JButton button2 = new JButton(Reset);
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textLabel.reset();
}
});
f.add(button, BorderLayout.SOUTH);
f.add(button2, BorderLayout.NORTH);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
create();
}
});
}
}
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;
/** @see http://stackoverflow.com/questions/2576909 */
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();
}
});
}
}