Динамические часы в Java

Я хочу реализовать часы в своей программе, чтобы отображать дату и время во время работы программы. Я просмотрел метод getCurrentTime() и Timer, но ни один из них, похоже, не делает то, что мне нужно.

Проблема в том, что я могу получить текущее время, когда программа загружается, но она никогда не обновляется. Любые предложения о том, что нужно изучить, будут очень признательны!


person jt153    schedule 02.06.2010    source источник
comment
Я не использую Swing широко, поэтому у меня нет подробного ответа, но Google, кажется, дает достаточно подсказок: google.com/search?q=java+swing+clock К сути: вам нужно обновлять часы самостоятельно каждый раз в фоновом потоке.   -  person BalusC    schedule 02.06.2010
comment
@BalusC, но вы много гуглите;)   -  person Bozho    schedule 02.06.2010


Ответы (6)


Что вам нужно сделать, это использовать Swing Timer класс.

Просто запустите его каждую секунду и обновите часы с текущим временем.

Timer t = new Timer(1000, updateClockAction);
t.start();

Это заставит updateClockAction срабатывать раз в секунду. Он будет работать на EDT.

Вы можете сделать updateClockAction похожим на следующее:

ActionListener updateClockAction = new ActionListener() {
  public void actionPerformed(ActionEvent e) {
      // Assumes clock is a custom component
      yourClock.setTime(System.currentTimeMillis()); 
      // OR
      // Assumes clock is a JLabel
      yourClock.setText(new Date().toString()); 
    }
}

Поскольку это обновляет часы каждую секунду, в худшем случае часы будут отключены на 999 мс. Чтобы увеличить это значение до худшего случая ошибки 99 мс, вы можете увеличить частоту обновления:

Timer t = new Timer(100, updateClockAction);
person jjnguy    schedule 02.06.2010
comment
Я провел тест, и обновление всегда отставало примерно на полсекунды с использованием javax.swing.Timer, но я не знаю, почему - person OscarRyz; 02.06.2010

Вы должны обновлять текст в отдельном потоке каждую секунду.

В идеале вы должны обновлять компонент Swing только в EDT (поток диспетчера событий), но после того, как я попробовал его на своем компьютере, используя Timer.scheduleAtFixRate дал мне лучшие результаты:

http://img175.imageshack.us/img175/8876/capturadepantalla201006o.png

Версия javax.swing.Timer всегда отставала примерно на полсекунды:

http://img241.imageshack.us/img241/2599/capturadepantalla201006.png

Я действительно не знаю, почему.

Вот полный источник:

package clock;

import javax.swing.*;
import java.util.*;
import java.text.SimpleDateFormat;

class Clock {
    private final JLabel time = new JLabel();
    private final SimpleDateFormat sdf  = new SimpleDateFormat("hh:mm");
    private int   currentSecond;
    private Calendar calendar;

    public static void main( String [] args ) {
        JFrame frame = new JFrame();
        Clock clock = new Clock();
        frame.add( clock.time );
        frame.pack();
        frame.setVisible( true );
        clock.start();
    }
    private void reset(){
        calendar = Calendar.getInstance();
        currentSecond = calendar.get(Calendar.SECOND);
    }
    public void start(){
        reset();
        Timer timer = new Timer();
        timer.scheduleAtFixedRate( new TimerTask(){
            public void run(){
                if( currentSecond == 60 ) {
                    reset();
                }
                time.setText( String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond ));
                currentSecond++;
            }
        }, 0, 1000 );
    }
}

Здесь измененный источник с использованием javax.swing.Timer

    public void start(){
        reset();
        Timer timer = new Timer(1000, new ActionListener(){
        public void actionPerformed( ActionEvent e ) {
                if( currentSecond == 60 ) {
                    reset();
                }
                time.setText( String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond ));
                currentSecond++;
            }
        });
        timer.start();
    }

Возможно, мне следует изменить способ вычисления строки с датой, но я не думаю, что проблема здесь в этом

Я читал, что начиная с Java 5 рекомендуется: ScheduledExecutorService Я оставляю вам задачу реализовать его.

person OscarRyz    schedule 02.06.2010
comment
Я не знаю, возможно, это было время запуска (чтобы попасть в EDT или что-то в этом роде), но я не мог их восстановить. - person OscarRyz; 02.06.2010

Похоже, у вас может быть концептуальная проблема. Когда вы создаете новый объект java.util.Date, он будет инициализирован текущим временем. Если вы хотите реализовать часы, вы можете создать компонент графического интерфейса, который постоянно создает новый объект Date и обновляет отображение последним значением.

У вас может возникнуть вопрос: как многократно выполнять что-то по расписанию? У вас может быть бесконечный цикл, который создает новый объект Date, а затем вызывает Thread.sleep(1000), чтобы он получал самое последнее время каждую секунду. Более элегантный способ сделать это — использовать TimerTask. Как правило, вы делаете что-то вроде:

private class MyTimedTask extends TimerTask {

   @Override
   public void run() {
      Date currentDate = new Date();
      // Do something with currentDate such as write to a label
   }
}

Затем, чтобы вызвать его, вы должны сделать что-то вроде:

Timer myTimer = new Timer();
myTimer.schedule(new MyTimedTask (), 0, 1000);  // Start immediately, repeat every 1000ms
person PhilDin    schedule 02.06.2010
comment
Этот код, вероятно, работает нормально, но поскольку вы используете Java.util.Timer, вам нужно убедиться, что вы используете SwingUtilities.invokeLater() для обновления графического интерфейса. - person jjnguy; 02.06.2010
comment
Определенно. Я намеренно расплывчато говорил о части «Сделай что-нибудь», я не хотел вводить слишком много вещей одновременно. - person PhilDin; 02.06.2010

Для тех, кто предпочитает аналоговый дисплей: JApplet аналоговых часов.

person trashgod    schedule 02.06.2010

Обратите внимание, что здесь используется метод scheduleAtFixedRate

        // Current time label
        final JLabel currentTimeLabel = new JLabel();
        currentTimeLabel.setFont(new Font("Monospace", Font.PLAIN, 18));
        currentTimeLabel.setHorizontalAlignment(JTextField.LEFT);

        // Schedule a task for repainting the time
        final Timer currentTimeTimer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                currentTimeLabel.setText(TIME_FORMATTER.print(System.currentTimeMillis()));
            }
        };

        currentTimeTimer.scheduleAtFixedRate(task, 0, 1000);
person shareef    schedule 17.04.2015

person    schedule
comment
Привет, добро пожаловать в Stack Overflow. Отвечая на вопрос, на который уже есть много ответов, не забудьте добавить дополнительную информацию о том, почему ваш ответ является существенным, а не просто повторяет то, что уже проверено исходным автором. Это особенно важно в ответах только на код, таких как тот, который вы предоставили. - person chb; 23.02.2019