Home ยป Java Stopwatch Using Swing Tutorial with code explanation

Java Stopwatch Using Swing Tutorial with code explanation

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!

You may also like