How do you change label text in java after a timer

2019-07-24 23:52发布

问题:

I have a timer with a delay of 5 seconds. I am trying to change the label named lblTimer after a second passes to act as a countdown. I am having issues with it as currently it only works at 5 seconds. Do you have any suggestionsuggestions?

protected void Addition() {
    //addition function 

    final int delay = 5000; //milliseconds

    ActionListener taskPerformer = new ActionListener() {
        @SuppressWarnings("unused")
        public void actionPerformed(ActionEvent evt) {
            //...Perform a task...
            frame.getContentPane().setBackground(Color.red);
        }
    };

    new Timer(delay, taskPerformer).start();
    Random RandomNumber = new Random();
    int number1 = RandomNumber.nextInt(12);
    int number2 = RandomNumber.nextInt(12);
    int number3 = RandomNumber.nextInt(12);
    lblAnswer.setText("");
    lblFirstNumber.setText(""+ number1);
    lblfunction1.setText("+");
    lblsecondNumber.setText(""+number2);
    lblfunction2.setText("+");
    lblthirdnumber.setText(""+number3);
    lblequals.setText("=");
    answer = number1+number2+number3;
    if(delay <= 1000){
        lblTimer.setText("1"); 
    }    
    else if(delay == 2000){
        lblTimer.setText("2"); 
    }    
    else if(delay == 3000){
        lblTimer.setText("3"); 
    } 
    else if(delay == 4000){
        lblTimer.setText("4"); 
    }    
    else if (delay == 5000){
        lblTimer.setText("5"); 
    }
}

回答1:

The answer to your question, that I assume is "why does this not work?", is that at no point do you recheck the elapsed time. The variable delay is always set at 5000, and never updated, also.

The stupid-ass solution:

lblTimer.setText("5");
Thread.sleep(1000)
lblTimer.setText("4");
Thread.sleep(1000)
lblTimer.setText("3");
Thread.sleep(1000)
lblTimer.setText("2");
Thread.sleep(1000)
lblTimer.setText("1");
Thread.sleep(1000)
lblTimer.setText("0");

Don't really do this, unless you need to satisfy your sick fetishes.

The four-liner

The same as above. Don't do this.

for (int i = secondsToWait; i >= 0; i--) {
    lblTimer.setText(i + "");
    Thread.sleep(1000);
}

The acceptable solution:

Use a Timer to schedule a task to be executed after a given period of time. You can use timers to also fire the same task multiple times at a given interval.

    Timer timer = new Timer();

    int secondsToWait = 5;
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            secondsToWait--;
            lblTimer.setText(secondsToWait + "");
            if (secondsToWait == 0) {
                timer.cancel();
                timer.purge();
            }
        }
    };

    lblTimer.setText(secondsToWait + "");
    timer.scheduleAtFixedRate(task, 1000, 1000);

The best solution:

Instead of a timer, use a ScheduledExecutorService. This is better because of the way ScheduledExecutorService works with threads as opposed to Timer. Google it.

    ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);

    int secondsToWait = 5;
    Runnable task = new Runnable() {
        @Override
        public void run() {
            secondsToWait--;
            lblTimer.setText(secondsToWait + "");
            if (secondsToWait == 0) {
                exec.shutdown();
            }
        }
    };

    lblTimer.setText(secondsToWait + "");
    exec.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS);

EDIT: As Stefan pointed out, for swing GUI applications a swing Timer would be the best pick.



回答2:

It should look something like this:

1) create Timer

2) create TimerTask and implement run method (updating your count variable and check if counter is zero. if it is zero, stop the timer)

3) schedule the task to run every second

int count = [INITVALUE];

...

public void startMethod() {
    final Timer timer = new Timer();
    timer.shedule(new TimerTask() {
          @Override
          public void run() {
             count--;
             lblTimer.setText(count+"");
             if (count == 0) {
               timer.cancel();
               timer.purge();
             }
          }
    },1000);

}


回答3:

Thumbs Up @Olavi Mustanoja your answer revealed an option I have never tried before now. As he lastly suggested on his edit the javax.swing.Timer comes in very handy if you're work with GUI.

import javax.swing.Timer;

private int secondsToWait = 5000; //Time in milliseconds
private Timer timer;

....

//The following section should be inside a method member
timer = new Timer(secondsToWait, e -> {
        if(secondsToWait == 0)
            timer.stop();//Stop if secondsToWait is already zero
        lblTimer.setText((secondsToWait/1000) + ""); //Update the label with the current sec
        timer.setDelay(secondsToWait);
        secondsToWait -= 1000; //Reduce time by 1sec each time
    });
    timer.start();

...