The StopWatch program displays the number of centiseconds since the Start button was pressed.
The display updates every centisecond.
The Start button resets the timer and disables itself, while enabling the Stop button.
The Stop button stops the timer, disables itself, and enables the Start button.
All functionality is contained within one file, without using the Model-View-Controller (MVC) pattern.
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
public class StopWatch extends JFrame {
private long startTime = 0;
private JFrame frame;
public StopWatch() {
frame = new JFrame("Digital Stopwatch");
JPanel buttonPanel = new JPanel();
JButton startButton = new JButton("Start");
JButton stopButton = new JButton("Stop");
JTextField timeField = new JTextField();
Timer timer = new Timer(10, null);
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
buttonPanel.add(startButton);
buttonPanel.add(stopButton);
stopButton.setEnabled(false);
timer = new Timer(10, e -> timeField.setText(calcTimeFieldText()));
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startTime = e.getWhen();
timer.start();
stopButton.setEnabled(true);
startButton.setEnabled(false);
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timeField.setText(calcTimeFieldText());
timer.stop();
stopButton.setEnabled(false);
startButton.setEnabled(true);
}
});
Container content = frame.getContentPane();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
timeField.setEditable(false);
content.add(timeField);
content.add(buttonPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public String calcTimeFieldText() {
long elapsed = System.currentTimeMillis() - startTime;
long centisecs = elapsed / 10;
long seconds = centisecs / 100;
long minutes = seconds / 60;
long hours = minutes / 60;
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumIntegerDigits(2);
String time = "" + nf.format(hours) + ":" + nf.format(minutes % 60) + ":"
+ nf.format(seconds % 60) + "." + nf.format(centisecs % 100);
return time;
}
public static void main(String[] args) {
new StopWatch();
}
}
Imports necessary Java AWT and Swing libraries:
java.awt.Container
java.awt.event.ActionEvent
java.awt.event.ActionListener
java.text.NumberFormat
javax.swing.BoxLayout
javax.swing.JButton
javax.swing.JFrame
javax.swing.JPanel
javax.swing.JTextField
javax.swing.Timer
The StopWatch
class contains:
A JFrame
named frame
with the title "Digital Stopwatch".
A long
variable startTime
initialized to 0.
StopWatch() Constructor
Creates a JPanel
called buttonPanel
.
Creates JButton
instances for "Start" and "Stop".
Creates a JTextField
called timeField
.
Declares a Timer
object.
Sets the layout of buttonPanel
to BoxLayout.X_AXIS
.
Adds startButton
and stopButton
to buttonPanel
.
Disables stopButton
initially using stopButton.setEnabled(false)
.
Creates a Timer
that executes every 100 milliseconds (every tenth of a second).
The Timer
updates timeField
with the calculated time using a lambda expression: timefield.setText(calcTimeFieldText());
ActionListeners for Buttons
startButton
's ActionListener
:
Sets startTime
to the event's time using e.getWhen()
.
Starts the timer
.
Enables stopButton
and disables startButton
.
stopButton
's ActionListener
:
Updates timeField
with the current time.
Stops the timer
.
Disables stopButton
and enables startButton
.
Setting up the Content Pane
Gets the content pane of the frame
.
Sets the layout of the content pane to BoxLayout.Y_AXIS
.
Adding Components and Frame Settings
Sets timeField
to non-editable using timeField.setEditable(false)
.
Adds timeField
and buttonPanel
to the content pane.
Sets the default close operation for the frame to exit the application using frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
.
Packs the frame to fit its contents using frame.pack()
.
Makes the frame visible using frame.setVisible(true)
.
calcTimeFieldText() Method
Calculates the elapsed time in milliseconds: long elapsed = System.currentTimeMillis() - startTime;
Converts elapsed time to centiseconds, seconds, minutes, and hours.
long centisecs = elapsed/10;
long seconds = centisecs/100;
long minutes = seconds/60;
long hours = minutes/60;
Uses NumberFormat
to ensure a minimum of two digits for each time unit.
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumIntegerDigits(2);
Formats the time as a string in the format "HH:MM:SS.CC".
String time = "" + nf.format(hours) + ":" + nf.format(minutes%60) + ":" + nf.format(seconds%60) + "." + nf.format(centisecs%100);
main() Method
Creates a new instance of the StopWatch
class to start the application.
new StopWatch();
Class Diagram of StopWatch Program
No details provided of Class Diagram
Anonymous Inner Classes vs Lambda Expressions
Anonymous Inner Classes:
Traditional way of implementing event listeners.
Requires creating a new instance of an interface or class.
Example:
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// code for start button
}
});
interface ActionListener {
public void actionPerformed(ActionEvent e);
}
Lambda Expressions:
More concise syntax for implementing functional interfaces.
Reduces boilerplate code.
Example:
startButton.addActionListener((ActionEvent e) -> {
// code for start button
});
The initial Traffic Light program mixes state management and display logic within a single class.
If the greenField
displays “ON”, the change()
method sets greenField
to “OFF” and amberField
to “ON”.
The code that models the state and the code that displays the state are intertwined.
Changing the way lights are displayed (e.g., using colored circles) requires modifying the state-changing logic.
This violates the design principle that each class should have only one responsibility.
Solution: Separate the state (model) from the display (view).
Model: Represents the state.
View: Displays the state.
When the state changes, the view should not need to change, and vice versa.
Responsibility of the View:
Display the lights.
Observe the model and update the lights when the model changes.
Responsibility of the Model:
Store the state.
Change the state when required.
Notify the view when the state changes.
The model does not depend on the view, allowing for multiple views.
Controller:
A separate class responsible for converting user inputs (e.g., mouse clicks) into actions that change the model.
May choose not to convert certain inputs.
Can also modify the view (e.g., disabling buttons).
Example:
The Run button disables the Change and Initialise buttons and enables the Stop button.
Controller Actions:
Manipulates the model.
Updates the views.
Queries the model.
Uses the Observer pattern.
View Subscribes: The view registers with the model by calling addObserver
.
Model Publishes: The model notifies its observers (views) of changes by calling setChanged()
followed by notifyObservers()
.
View Requests State: The view retrieves the new state from the model by calling methods like getRed()
, getGreen()
, etc.
TLModel
class extends Observable
.
Attributes:
private boolean red
private boolean amber
private boolean green
Getter methods to access the state:
public boolean getRed()
public boolean getAmber()
public boolean getGreen()
Implements the traffic light state transition logic.
State transitions:
Red -> Amber
Red & Amber -> Green
Green -> Amber
Otherwise -> Red
Notifies observers after the state change:
setChanged();
notifyObservers();
Initializes the traffic light to the red state.
red = true;
amber = false;
green = false;
Notifies observers after initialization.
Calls the initialise()
method to set the initial state.
TLView
class implements the Observer
interface.
Attributes:
private static final Dimension PANEL_SIZE = new Dimension(200,200);
private TLModel model
private TLController controller
private JFrame frame
private JPanel panel
private JTextField redField
, amberField
, greenField
private JLabel redLabel
, amberLabel
, greenLabel
private JButton changeButton
, initialiseButton
Takes a TLModel
and TLController
as arguments.
Sets the model and controller.
Registers the view as an observer of the model: model.addObserver(this);
Calls createControls()
to initialize the UI components.
Sets the view for the controller using controller.setView(this);
Calls update(model, null)
to set the initial display.
Creates the main JFrame
.
Sets the default close operation to exit the application.
Gets the content pane and sets its layout to BoxLayout.X_AXIS
.
Calls createPanel()
to create the panel with the traffic light components.
Adds the panel to the content pane.
Packs the frame and sets it to non-resizable.
Makes the frame visible.
Creates a JPanel
and sets its layout to GridLayout(4,2)
.
Sets the text fields to non-editable.
Adds labels and text fields for red, amber, and green lights.
Creates and adds changeButton
and initialiseButton
with their respective action listeners that call the appropriate controller methods.
Sets the preferred size of the panel using panel.setPreferredSize(PANEL_SIZE);
Implements the update
method from the Observer
interface.
Updates the text fields based on the model's state