简体   繁体   中英

Java Countdown Timer reset issue

I have coded a countdown timer in java. It counts down from whatever number a user selects in a combo box, there are 3 of them (hour, minute, second). This part is working perfectly fine.

The issue comes when I press my "Reset" button. It clears the labels I use to display the time left, and makes them display "00". But when I press start again, it recalls where it last was in terms of seconds left and starts there.

Please help!!

Here is my code for the timer:

private void JButtonActionPerformed(java.awt.event.ActionEvent evt) {                                        

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


        @Override
        public void actionPerformed(ActionEvent e){

        onoff = true; 


        if(hours == 1 && min == 0 && sec ==0){

            repaint();
            hours--;
            lblHours.setText("00");
            min=59;
            sec=60;

        }

         if(sec == 0 && min <= 59 && min>0){   

             sec=60;
             min--;
             lblHours.setText("00");

         }

         if(sec == 0 && hours == 0 && min<=0){

             repaint();
             JOptionPane.showMessageDialog(rootPane, "You have run out of time and did not manage to escape!", "Time is up!!", 0 );
             hours = 0; min = 0; sec = 0;
             timer.stop();
         }

         else{

             sec--;
             repaint();

             if (sec<10){

             lblSeconds.setText("0"+sec);
             repaint();
             flag = false;

             }
             if (hours==0){

                 repaint();
                 lblHours.setText("00");

             if (min<10)

                 repaint();
                 lblMinutes.setText("0"+min);

                 if (sec<10)

                     lblSeconds.setText("0"+sec);

                 else

                     lblSeconds.setText(""+sec);


             }
             if(flag){
             lblHours.setText(""+hours);
             lblMinutes.setText(""+min);
             lblSeconds.setText(""+sec);
             repaint();

             }


         }
    }

});

    timer.start();


} 

And my code for the reset button is here:

    onoff =false;


    timer.stop();
    repaint();

    lblHours.setText("00");
    lblMinutes.setText("00");
    lblSeconds.setText("00");
    repaint();

I know I go a bit crazy with the repaint(); but I have no idea how often I am meant to use it lol.

Any help/guidance would be greatly appreciated.

No where in you available, out-of-context, code do you reset the variables hours , min , second .

This could have been solved by simply putting in some print statements around your data and probably some simple desk check of your states.

Having said that, this is some what of a naive approach.

Swing Timer (and even Thread.sleep ) only guarantee "at least" duration.

Okay, so you're not developing a super high-resolution timer, but you still need to understand that this can cause a "drift" to occur, especially over a large period.

A "better" solution would be to calculate the time passed since the timer was started. Lucky for us, Java now includes a lot of support for this in the form of its newer date/time API.

The following example makes uses of a simple "stop watch" concept, which is simply the amount of time which has passed since it was started. It itself doesn't actual tick, making it very efficient.

But how is a forward moving clock going to help you? A lot actually. You can calculate the time remaining but subtracting the desired run time from the current amount of time passed (since it was started) and you have a count down. Simple.

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

  public class StopWatch {

    private Instant startTime;
    private Duration totalRunTime = Duration.ZERO;

    public void start() {
      startTime = Instant.now();
    }

    public void stop() {
      Duration runTime = Duration.between(startTime, Instant.now());
      totalRunTime = totalRunTime.plus(runTime);
      startTime = null;
    }

    public void pause() {
      stop();
    }

    public void resume() {
      start();
    }

    public void reset() {
      stop();
      totalRunTime = Duration.ZERO;
    }

    public boolean isRunning() {
      return startTime != null;
    }

    public Duration getDuration() {
      Duration currentDuration = Duration.ZERO;
      currentDuration = currentDuration.plus(totalRunTime);
      if (isRunning()) {
        Duration runTime = Duration.between(startTime, Instant.now());
        currentDuration = currentDuration.plus(runTime);
      }
      return currentDuration;
    }
  }

  public static void main(String[] args) throws InterruptedException {
    new Test();
  }

  public Test() {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        try {
          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
          ex.printStackTrace();
        }

        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new TestPane());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    });
  }

  public class TestPane extends JPanel {

    private JLabel label;
    private JButton btn;

    private StopWatch stopWatch = new StopWatch();
    private Timer timer;

    public TestPane() {
      label = new JLabel("...");
      btn = new JButton("Start");

      setLayout(new GridBagLayout());
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridwidth = GridBagConstraints.REMAINDER;

      add(label, gbc);
      add(btn, gbc);

      timer = new Timer(500, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          Duration runningTime = Duration.of(10, ChronoUnit.MINUTES);
          Duration remainingTime = runningTime.minus(stopWatch.getDuration());
          System.out.println("RemainingTime = " + remainingTime);
          if (remainingTime.isZero() || remainingTime.isNegative()) {
            timer.stop();
            label.setText("0hrs 0mins 0secs");
          } else {
            long hours = remainingTime.toHours();
            long mins = remainingTime.toMinutesPart();
            long secs = remainingTime.toSecondsPart();
            label.setText(String.format("%dhrs %02dmins %02dsecs", hours, mins, secs));
          }
        }
      });
      timer.start();

      btn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          if (stopWatch.isRunning()) {
            stopWatch.pause();
            btn.setText("Start");
          } else {
            stopWatch.resume();
            btn.setText("Pause");
          }
        }
      });

    }

    @Override
    public Dimension getPreferredSize() {
      return new Dimension(200, 200);
    }

  }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM