In this tutorial, we will build a simple Stopwatch application in Java using Swing for the graphical user interface (GUI).
The stopwatch will have Start, Stop, and Reset functionalities, and will display the elapsed time in seconds and milliseconds.
This is the app you will create in action
Features of the Stopwatch App:
Here are the features we want in the app, fairly obvious for a stopwatch.
Start: Starts the stopwatch and updates the displayed time every millisecond.
Stop: Stops the stopwatch without resetting the elapsed time.
Reset: Resets the stopwatch to 0.
The app will use Swing components like JFrame, JButton, and JLabel to create the user interface.
Complete Code
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class StopwatchApp extends JFrame { private JLabel timeLabel; private JButton startButton, stopButton, resetButton; private Timer timer; private long startTime; private long elapsedTime = 0; // Tracks the total elapsed time // Constructor to set up the GUI public StopwatchApp() { setTitle("Stopwatch"); setSize(300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); // Center the window on the screen // Initialize components timeLabel = new JLabel("00:00:000", SwingConstants.CENTER); timeLabel.setFont(new Font("Serif", Font.BOLD, 36)); startButton = new JButton("Start"); stopButton = new JButton("Stop"); resetButton = new JButton("Reset"); // Disable stop and reset buttons initially stopButton.setEnabled(false); resetButton.setEnabled(false); // Set up the layout JPanel buttonPanel = new JPanel(); buttonPanel.add(startButton); buttonPanel.add(stopButton); buttonPanel.add(resetButton); setLayout(new BorderLayout()); add(timeLabel, BorderLayout.CENTER); add(buttonPanel, BorderLayout.SOUTH); // Timer to update the stopwatch every millisecond timer = new Timer(1, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { elapsedTime = System.currentTimeMillis() - startTime; updateDisplay(); } }); // Add action listeners to the buttons startButton.addActionListener(new StartButtonListener()); stopButton.addActionListener(new StopButtonListener()); resetButton.addActionListener(new ResetButtonListener()); setVisible(true); } // Method to update the time display private void updateDisplay() { long seconds = (elapsedTime / 1000) % 60; long minutes = (elapsedTime / (1000 * 60)) % 60; long milliseconds = elapsedTime % 1000; timeLabel.setText(String.format("%02d:%02d:%03d", minutes, seconds, milliseconds)); } // Action listener for the Start button private class StartButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { startTime = System.currentTimeMillis() - elapsedTime; // Adjust for any existing elapsed time timer.start(); // Start the timer startButton.setEnabled(false); // Disable the start button stopButton.setEnabled(true); // Enable the stop button resetButton.setEnabled(false); // Disable the reset button } } // Action listener for the Stop button private class StopButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { timer.stop(); // Stop the timer startButton.setEnabled(true); // Enable the start button stopButton.setEnabled(false); // Disable the stop button resetButton.setEnabled(true); // Enable the reset button } } // Action listener for the Reset button private class ResetButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { timer.stop(); // Stop the timer elapsedTime = 0; // Reset elapsed time updateDisplay(); // Update the display to show "00:00:000" startButton.setEnabled(true); // Enable the start button stopButton.setEnabled(false); // Disable the stop button resetButton.setEnabled(false); // Disable the reset button } } // Main method to run the app public static void main(String[] args) { SwingUtilities.invokeLater(() -> new StopwatchApp()); } }
Explanation of the Code
1. Import Statements
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; javax.swing.*: Provides Swing components like JFrame, JButton, and JLabel for creating the GUI. java.awt.*: Provides layout and graphical utilities (BorderLayout, Font). java.awt.event.*: Provides event listener classes to handle button clicks and timer events.
2. Class Declaration and Instance Variables
public class StopwatchApp extends JFrame { private JLabel timeLabel; private JButton startButton, stopButton, resetButton; private Timer timer; private long startTime; private long elapsedTime = 0; }
JLabel timeLabel: Displays the current time (minutes, seconds, and milliseconds).
JButton startButton, stopButton, resetButton: Buttons for starting, stopping, and resetting the stopwatch.
Timer timer: A Swing Timer that updates the time display every millisecond.
long startTime: Tracks the time when the stopwatch starts.
long elapsedTime: Tracks the total elapsed time, even after stopping.
3. Constructor
public StopwatchApp() { setTitle("Stopwatch"); setSize(300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); // Center the window on the screen timeLabel = new JLabel("00:00:000", SwingConstants.CENTER); timeLabel.setFont(new Font("Serif", Font.BOLD, 36)); startButton = new JButton("Start"); stopButton = new JButton("Stop"); resetButton = new JButton("Reset"); stopButton.setEnabled(false); resetButton.setEnabled(false); JPanel buttonPanel = new JPanel(); buttonPanel.add(startButton); buttonPanel.add(stopButton); buttonPanel.add(resetButton); setLayout(new BorderLayout()); add(timeLabel, BorderLayout.CENTER); add(buttonPanel, BorderLayout.SOUTH); timer = new Timer(1, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { elapsedTime = System.currentTimeMillis() - startTime; updateDisplay(); } }); startButton.addActionListener(new StartButtonListener()); stopButton.addActionListener(new StopButtonListener()); resetButton.addActionListener(new ResetButtonListener()); setVisible(true); }
Frame Setup:
setTitle(“Stopwatch”): Sets the window title.
setSize(300, 200): Sets the window size.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE): Ensures the app exits when the window is closed.
setLocationRelativeTo(null): Centers the window on the screen.
Label Setup:
timeLabel = new JLabel(“00:00:000”, SwingConstants.CENTER): Initializes the label with the default “00:00:000” text.
timeLabel.setFont(new Font(“Serif”, Font.BOLD, 36)): Sets the font for the time label.
Button Setup:
stopButton.setEnabled(false) and resetButton.setEnabled(false): The stop and reset buttons are disabled initially.
Layout Setup:
setLayout(new BorderLayout()): Uses a BorderLayout to position the components.
add(timeLabel, BorderLayout.CENTER): Adds the label to the center of the window.
add(buttonPanel, BorderLayout.SOUTH): Adds the button panel at the bottom of the window.
Timer Setup:
timer = new Timer(1, …): The Timer is set to update the elapsed time every millisecond (1 ms).
Inside the timer’s ActionListener, we calculate the elapsed time and call updateDisplay() to refresh the display.
4. updateDisplay() Method
private void updateDisplay() { long seconds = (elapsedTime / 1000) % 60; long minutes = (elapsedTime / (1000 * 60)) % 60; long milliseconds = elapsedTime % 1000; timeLabel.setText(String.format("%02d:%02d:%03d", minutes, seconds, milliseconds)); } elapsedTime / 1000: Converts milliseconds to seconds. elapsedTime / (1000 * 60): Converts milliseconds to minutes. elapsedTime % 1000: Extracts the remaining milliseconds. String.format("%02d:%02d:%03d", ...): Formats the time as mm:ss:SSS, where mm is minutes, ss is seconds, and SSS is milliseconds.
5. Action Listener for the Start Button
private class StartButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { startTime = System.currentTimeMillis() - elapsedTime; // Adjust for any existing elapsed time timer.start(); // Start the timer startButton.setEnabled(false); // Disable the start button stopButton.setEnabled(true); // Enable the stop button resetButton.setEnabled(false); // Disable the reset button } } startTime = System.currentTimeMillis() - elapsedTime: Adjusts the start time to account for any elapsed time (if the stopwatch was stopped and restarted). timer.start(): Starts the timer. startButton.setEnabled(false): Disables the start button while the stopwatch is running. stopButton.setEnabled(true): Enables the stop button. resetButton.setEnabled(false): Disables the reset button.
6. Action Listener for the Stop Button
private class StopButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { timer.stop(); // Stop the timer startButton.setEnabled(true); // Enable the start button stopButton.setEnabled(false); // Disable the stop button resetButton.setEnabled(true); // Enable the reset button } } timer.stop(): Stops the timer. startButton.setEnabled(true): Re-enables the start button. stopButton.setEnabled(false): Disables the stop button after stopping the timer. resetButton.setEnabled(true): Enables the reset button after stopping the timer.
7. Action Listener for the Reset Button
private class ResetButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { timer.stop(); // Stop the timer elapsedTime = 0; // Reset the elapsed time updateDisplay(); // Update the display to show "00:00:000" startButton.setEnabled(true); // Enable the start button stopButton.setEnabled(false); // Disable the stop button resetButton.setEnabled(false); // Disable the reset button } } timer.stop(): Stops the timer. elapsedTime = 0: Resets the elapsed time to 0. updateDisplay(): Updates the display to show "00:00:000". startButton.setEnabled(true): Re-enables the start button. stopButton.setEnabled(false): Disables the stop button. resetButton.setEnabled(false): Disables the reset button after resetting.
8. Main Method
public static void main(String[] args) { SwingUtilities.invokeLater(() -> new StopwatchApp()); } SwingUtilities.invokeLater(): Ensures that the GUI is created and updated on the Event Dispatch Thread (EDT), which is necessary for Swing applications. new StopwatchApp(): Creates and launches the stopwatch app.
Customization Ideas
1. Add Lap Functionality
Add a Lap button to record the current time while the stopwatch is running and display the laps in a list (JList or JTextArea).
2. Change the Display Format
Allow the user to choose between different time formats (e.g., hours, minutes, seconds, milliseconds) using a dropdown or radio buttons.
3. Custom Styling
Customize the appearance of the buttons, label, and window (e.g., change colors, add icons).
4. Sound on Start/Stop
Add a small beep sound or sound when the user starts or stops the stopwatch.
Conclusion
This simple Stopwatch App in Java using Swing demonstrates how to build a GUI application with basic time-keeping functionality. The app includes start, stop, and reset functionality, and the time is displayed with precision in milliseconds.
This project introduces:
Using Swing to create a graphical interface.
Handling timers with Timer to update the time display.
Implementing event-driven programming with action listeners for buttons.
Feel free to extend this project with additional features or customize the UI to suit your needs!