Solution for
Programming Exercise 7.6
THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to
the following exercise from this on-line
Java textbook.
Exercise 7.6:
The StopWatch component from Section 7.4
displays the text "Timing..." when the stop watch is running. It would
be nice if it displayed the elapsed time since the stop watch
was started. For that, you need to create a Timer. Add
a Timer to the original source code, StopWatch.java,
to display the elapsed time in seconds. Create the timer in
the mousePressed() routine when the stop watch is started.
Stop the timer in the mousePressed() routine when the stop watch
is stopped. The elapsed time won't be very accurate anyway, so just
show the integral number of seconds. You only need to set the text a
few times per second. For my Timer method, I use a delay of 100 milliseconds
for the timer. Here is an applet that tests my solution
to this exercise:
Discussion
This one is almost too easy. (The hardest part is that I
referred to the stop watch as a "timer" in my program, and this
could be confused with a Timer object.)
The guidelines for using Timers
can be found in Section 7.6. An instance
variable named timer of type Timer is added to the
class. The timer is started when the stop watch is started and
is stopped when the stop watch is stopped. Both of these things
happen in the mousePressed() method. I could have created
a new timer each time the stop watch is started, but I decided to
reuse a single timer. The first time the stop watch is started, a Timer
object is created and started. After that, the same Timer
object is simply restarted. I can tell the difference between
these two cases since the first time, the timer will be null:
if (timer == null) {
timer = new Timer(100,this);
timer.start();
}
else
timer.restart();
The class is declared to implement ActionListener
so that it can respond to events from the timer. (As always,
it would probably be better style to create another object
to do the listening.) The actionPerformed()
method just has to set the text on the label to show how
much time has passed since the stop watch was started. The starting
time of the stop watch is in the instance variable startTime.
The current time is given by System.currentTimeMillis(),
so the elapsed time, in milliseconds, is just
System.currentTimeMillis() - startTime. This has to
be divided by 1000 to give the number of seconds. (Remember that
dividing an integer by an integer always gives an integer. The
answer is rounded down to the nearest integral number of seconds.)
The actionPerformed() method simply does this calculation
and then sets the text of the label.
The complete source code is shown below, followed by the source
code for the little applet that tests the component. The applet
sets the fonts and colors of the stop watch component.
The Solution
The improved StopWatch component, with changes shown
in red:
/*
A component that acts as a simple stop-watch. When the user clicks
on it, this component starts timing. When the user clicks again,
it displays the time between the two clicks. Clicking a third time
starts another timer, etc. While it is timing, the label just
displays the whole number of seconds since the timer was started.
*/
import java.awt.event.*;
import javax.swing.*;
public class StopWatchRunner extends JLabel
implements MouseListener, ActionListener {
private long startTime; // Start time of stopwatch.
// (Time is measured in milliseconds.)
private boolean running; // True when the stopwatch is running.
private Timer timer; // A timer that will generate events
// while the stopwatch is running
public StopWatchRunner() {
// Constructor.
super(" Click to start timer. ", JLabel.CENTER);
addMouseListener(this);
}
public void actionPerformed(ActionEvent evt) {
// This will be called when an event from the
// timer is received. It just sets the stopwatch
// to show the amount of time that it has been running.
// Time is rounded down to the nearest second.
long time = (System.currentTimeMillis() - startTime) / 1000;
setText("Running: " + time + " seconds");
}
public void mousePressed(MouseEvent evt) {
// React when user presses the mouse by
// starting or stopping the stopwatch. Also start
// or stop the timer.
if (running == false) {
// Record the time and start the stopwatch.
running = true;
startTime = evt.getWhen(); // Time when mouse was clicked.
setText("Running: 0 seconds");
if (timer == null) {
timer = new Timer(100,this);
timer.start();
}
else
timer.restart();
}
else {
// Stop the stopwatch. Compute the elapsed time since the
// stopwatch was started and display it.
timer.stop();
running = false;
long endTime = evt.getWhen();
double seconds = (endTime - startTime) / 1000.0;
setText("Time: " + seconds + " sec.");
}
}
public void mouseReleased(MouseEvent evt) { }
public void mouseClicked(MouseEvent evt) { }
public void mouseEntered(MouseEvent evt) { }
public void mouseExited(MouseEvent evt) { }
} // end StopWatchRunner
A small applet to test the component:
/*
A trivial applet that tests the StopWatchRunner component.
The applet just creates and shows a StopWatchRunner.
*/
import java.awt.*;
import javax.swing.*;
public class TestStopWatch extends JApplet {
public void init() {
StopWatchRunner watch = new StopWatchRunner();
watch.setFont( new Font("SansSerif", Font.BOLD, 24) );
watch.setBackground(Color.white);
watch.setForeground( new Color(180,0,0) );
watch.setOpaque(true);
getContentPane().add(watch, BorderLayout.CENTER);
}
}
[ Exercises
| Chapter Index
| Main Index
]