Как мне дождаться окончания таймера Java? - PullRequest
2 голосов
/ 10 декабря 2011

У меня есть графический интерфейс Java, в котором я пытаюсь реализовать таймер обратного отсчета. У меня есть ряд задач, каждая из которых должна выполняться последовательно внутри цикла for. Я смог успешно использовать таймер свинга для таймера обратного отсчета, но как только я попытаюсь поставить его в цикл, я не смогу обновить его, не заморозив графический интерфейс.

Вот SSCCE того, что у меня сейчас работает. Основная проблема в этом примере - запустить три 30-секундных таймера параллельно. Что я хочу сделать, так это запустить три 30-секундных таймера последовательно или, другими словами, ему следует подождать, пока один таймер завершит работу, прежде чем начинать следующий. Все, что я сделал, чтобы попытаться дождаться окончания таймера, приводит к зависанию графического интерфейса.

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.security.auth.callback.Callback;
import javax.swing.*;

public class SwingTester extends JFrame {
  public SwingTester() {
    JPanel panel = new JPanel();
    getContentPane().add(panel);
    panel.setLayout(new GridLayout(1,3));
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    // Add the components
    jLblTimer = new JLabel("00:30");
    jLblSet = new JLabel("Set #1");
    jBtnStart = new JButton("Start!");
    jBtnStart.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {jBtnStartActionPerformed(evt);}
    });
    // Add the labels
    panel.add(jLblTimer); panel.add(jLblSet); panel.add(jBtnStart);
    pack();
  }
  private void jBtnStartActionPerformed(ActionEvent evt) {
    for (int ss=0; ss<3; ss++) {
        // Change the set name
        jLblSet.setText("Set #" + Integer.toString(ss+1));
        // Setup the counter to begin the countdown
        counter = 30;
        timer = new Timer(1000, startCycle());
        timer.start();
        // I want to wait here until the timer is done, nothing I've done
        // works without freezing the GUI.
    }
  }
  public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        new SwingTester().setVisible(true);
      }
    });
  }
  private Action startCycle() {
    return new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            new ClockTask(null).execute();
        }
    };
  }
  class ClockTask extends SwingWorker<Void, String> {
  private Callback callback;
  public ClockTask(Callback callback) {
    this.callback = callback;
  }
  @Override
  protected Void doInBackground() throws Exception {
    if (counter >= 0) {
      int millis = counter*1000;
      String time = String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes(millis),
        TimeUnit.MILLISECONDS.toSeconds(millis) -
        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
        );
      publish(time); // call publish which will call process() method in EDT
      counter--;
    } else {
      // this.callback.call();
      this.callback.notify();
      timer.stop();
    }
    return(null);
  }
  @Override
  protected void process(List<String> times) {
    String lastTime = times.get(times.size()-1);
    jLblTimer.setText(lastTime); // just update ui with lastTimer, ohters are ignorable 
  }
  @Override
  protected void done() {
    super.done();
  }

  // private interface Callback {
  //   void call();
  // }
  }
  private javax.swing.JLabel jLblTimer;
  private javax.swing.JLabel jLblSet;
  private javax.swing.JButton jBtnStart;
  private javax.swing.Timer timer;
  private int counter;

}

Я также пытался использовать функцию сна, чтобы просто дождаться окончания обратного отсчета, но это мешает обновлению графического интерфейса. Любые предложения приветствуются. Как вы, вероятно, можете сказать из моего кода, я не программист.

Ответы [ 2 ]

3 голосов
/ 10 декабря 2011

Ниже описано, как вам нужно изменить SwingWorker

class ClockTask extends SwingWorker<Void, String> {

    private Callback callback;

    public ClockTask(Callback callback) {
        this.callback = callback;
    }

    @Override
    protected Void doInBackground() throws Exception {
        if (counter >= 0) {
            int millis = counter*1000;
            String time = String.format("%02d:%02d", 
                TimeUnit.MILLISECONDS.toMinutes(millis),
                TimeUnit.MILLISECONDS.toSeconds(millis) - 
                TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
            );

            //jLblTimer.setText(time); // dont update UI in backgroudn thread
            publish(time); // call publish which will call process() method in EDT

            counter--;
        } else {
            this.callback.call();
        }
        return(null);
    }

    /*
     * this  method will be called in EDT and will not freeze your UI ;)
     */
    @Override
    protected void process(List<String> times) {
        String lastTime = times.get(times.size()-1);
        jLblTimer.setText(lastTime); // just update ui with lastTimer, ohters are ignorable 
    }

    @Override
    protected void done() {
        super.done();
    }

    private interface Callback {
        void call();
    }

}

Вы должны потратить немного больше времени с JavaDoc SwingWorker

0 голосов
/ 10 декабря 2011

Есть несколько способов сделать это. Обычно вы можете создать объект, передать его фоновой работе, после того как фоновая работа завершится, он использует объект, чтобы сообщить вам результат и позволить вам выполнить остальную работу.

private class ClockTask extends SwingWorker<Void, Void> {

    private Callback _callback;

    public ClockTask(Callback callback) {
        this._callback = callback;
    }

    @Override
    protected Void doInBackground() throws Exception {
        if (counter >= 0) {
            int millis = counter*1000;
            String time = String.format("%02d:%02d", 
                TimeUnit.MILLISECONDS.toMinutes(millis),
                TimeUnit.MILLISECONDS.toSeconds(millis) - 
                TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
            );
            jLblTimer.setText(time);
            counter--;
        } else {
            this._callback.notify();
        }
        return(null);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...