What I took some time to work on is a program showing time elapsed, or time remaining, from where the user clicks the start button, much like a stopwatch or a chronometer which measures time until you stop and reset. Other examples of measuring time elapsed are those lap times in racing games and time limits, with milliseconds, in other games.
I'm running into some trouble, though, because my own stopwatch is not running at the same rate as actual time. It takes longer than one second for my timer to run one second down or up.
The code is right here: (the GUI works perfectly; I'm more concerned about how to control the values to show the time elapsed in a way that for every second passed, the time displayed on the JLabel
is one second less. I cannot modify the argument that's passed into Thread.sleep
because it will make the timer much worse.)
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.text.DecimalFormat;
import java.util.concurrent.*;
public class StopwatchGUI3 extends JFrame
{
private static final long serialVersionUID = 3545053785228009472L;
// GUI Components
private JPanel panel;
private JLabel timeLabel;
private JPanel buttonPanel;
private JButton startButton;
private JButton resetButton;
private JButton stopButton;
// Properties of Program.
private byte centiseconds = 0;
private byte seconds = 30;
private short minutes = 0;
private Runnable timeTask;
private Runnable incrementTimeTask;
private Runnable setTimeTask;
private DecimalFormat timeFormatter;
private boolean timerIsRunning = true;
private ExecutorService executor = Executors.newCachedThreadPool();
public StopwatchGUI3()
{
panel = new JPanel();
panel.setLayout(new BorderLayout());
timeLabel = new JLabel();
timeLabel.setFont(new Font("Consolas", Font.PLAIN, 13));
timeLabel.setHorizontalAlignment(JLabel.CENTER);
panel.add(timeLabel);
buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
startButton = new JButton("Start");
startButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
if (!timerIsRunning)
timerIsRunning = true;
executor.execute(timeTask);
}
});
buttonPanel.add(startButton);
resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
timerIsRunning = false;
centiseconds = 0;
seconds = 30;
minutes = 0;
timeLabel.setText(timeFormatter.format(minutes) + ":"
+ timeFormatter.format(seconds) + "."
+ timeFormatter.format(centiseconds));
}
});
buttonPanel.add(resetButton);
stopButton = new JButton("Stop");
stopButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
timerIsRunning = false;
}
});
buttonPanel.add(stopButton);
panel.add(buttonPanel, BorderLayout.SOUTH);
timeFormatter = new DecimalFormat("00");
timeTask = new Runnable(){
public void run()
{
while(timerIsRunning)
{
executor.execute(incrementTimeTask);
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
};
incrementTimeTask = new Runnable(){
public void run()
{
if (centiseconds > 0)
centiseconds--;
else
{
if (seconds == 0 && minutes == 0)
timerIsRunning = false;
else if (seconds > 0)
{
seconds--;
centiseconds = 99;
}
else if (minutes > 0)
{
minutes--;
seconds = 59;
centiseconds = 99;
}
}
executor.execute(setTimeTask);
}
};
setTimeTask = new Runnable(){
public void run()
{
timeLabel.setText(timeFormatter.format(minutes) + ":"
+ timeFormatter.format(seconds) + "."
+ timeFormatter.format(centiseconds));
}
};
timeLabel.setText(timeFormatter.format(minutes) + ":"
+ timeFormatter.format(seconds) + "."
+ timeFormatter.format(centiseconds));
add(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setTitle("StopwatchGUI.java");
pack();
setVisible(true);
}
public static void main(String[] args)
{
new StopwatchGUI3();
}
}
There's gotta be another way to make the timer in sync with real time, just like a real stopwatch, instead of having to rely on three separate threads, which I think are too many for such a large programming project, but okay at entry level for now. (oh, by the way, the DecimalFormat
class is to format the numbers properly like a real stopwatch, though there are no decimal values to round. It's only until now, at the time I posted this, that there exists a text class called SimpleDateFormat
.)
In other words, I want this program to be just a real stopwatch. If this is not the case, then how do you create, or use, a stopwatch, in Java games, for example?
See Question&Answers more detail:os