0

I am creating a simple stopwatch program in GUI for Java. I added a start button where it begins the stopwatch in "seconds:nano" format.

I implemented another button, Reset which is to stop the timer and reset to "0:0" whenever I want. I tried using timer.stop() but it couldn't get the stopwatch to reset. May I know what is problem I made?

Code:

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class GuiStopwatch {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Stopwatch");

        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        JPanel panel = new JPanel();

        panel.setLayout(null);

        JButton Startbtn = new JButton("START");  
        JButton Stopbtn = new JButton("STOP");
        JButton Reset = new JButton("RESET");
        JLabel time = new JLabel("Time shows here");
        panel.add(Startbtn);
        panel.add(Stopbtn);
        panel.add(Reset);
        panel.add(time);
        Startbtn.setBounds(50, 150, 100, 35);
        Stopbtn.setBounds(50, 200, 100, 35);
        Reset.setBounds(50, 250, 100, 35);
        time.setBounds(50, 350, 100, 35);
        time.setBackground(Color.black);
        time.setForeground(Color.red);
        frame.add(panel);

        Startbtn.addActionListener(new ActionListener() {
            Instant start;

            @Override
            public void actionPerformed(ActionEvent e) {
                start = Instant.now();

                Timer timer = new Timer(1,new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {

                        time.setText( Duration.between(start, Instant.now()).getSeconds() +  ":" + Duration.between(start, Instant.now()).getNano() );
                    }
                });
                timer.start();
            }
        });

        Reset.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Timer timer1 = new Timer(1,new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        time.setText( "test" );
                    }
                });
                timer1.stop();   
            }
        });
    }
}

Any help would be appreciated.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Lord Jesus
  • 81
  • 8
  • 1) Please learn common Java nomenclature (naming conventions - e.g. `EachWordUpperCaseClass`, `firstWordLowerCaseMethod()`, `firstWordLowerCaseAttribute` unless it is an `UPPER_CASE_CONSTANT`) and use it consistently. 2) Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). – Andrew Thompson May 17 '18 at 15:10

1 Answers1

1

You are creating a new Timer inside actionPerformed on each of the Start and the Reset button. So if I click Start three times and Reset once, there are four timers. I don’t think you intended that. When I press Reset, you stop a different timer from the one that was started on Start.

You just need one timer in total. Declare it outside the action listeners so both action listeners may manipulate it.

You have got no action listener on your Stop button yet, but you were probably aware of that already.

By the way, you are able to reset the counter: at least on my computer, if I press Start a second time, the counter seems to start over from 0. I believe it comes from this line:

            start = Instant.now();

There may be other issues with your code, as has been mentioned in comments. With the above I am trying to answer the question you are asking only.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • One thing I noticed with Instant.now() is that if I pause/stop the timer, the timer stops but if I resume it, the timer jumps to the current timer that is being delayed. For example, I pause it at 10s , and i leave it for 5 seconds before I hit resume, the timer is start at 15seconds instead of resuming from 10s. – Lord Jesus May 17 '18 at 19:04
  • That sounds right, @LordJesus. `start` still keeps the point in time when the timer was first started. One way to be able to resume would be, when the timer is paused, you store the `Duration` from `start` to current time. Then on resuming, you calculate backward to set start to this duration ago. – Ole V.V. May 17 '18 at 19:10
  • So ideally I should add another button for resume? Right now , I have three buttons, Start, Pause and Reset. When I hit Pause , it works and once I hit Start again, it resumes but not from the time I paused it. – Lord Jesus May 17 '18 at 19:19
  • If you think you have the right interface, first try to make that work. If Start should work as resuming in the case where some number of seconds has been reached, a solution is: when Start is pressed, check if there’s a saved `Duration`. If not, count from zero. If there is, calculate an imaginary start time as I described before. – Ole V.V. May 17 '18 at 19:39
  • On a side note, do you think this is the best way to implement a stopwatch or are there alternatives to implement it as well? – Lord Jesus May 17 '18 at 19:58
  • I am sure you can find examples out there and compare to your own. I agree in [Andrew Thompson’s comment under the question](https://stackoverflow.com/questions/50393827/how-to-add-stopwatch-in-hhmmss-format/50396734#comment87805445_50393827). My style would be designing a subclass of `JFrame`, but that’s a matter of taste. – Ole V.V. May 18 '18 at 06:33