Используйте таймеры для изменения пользовательского интерфейса

1

Я пытался сделать простые часы, которые обновляются раз в секунду, чтобы снизить стоимость процессора. Thread.sleep() я попытался использовать Thread.sleep(), но при использовании в цикле в графическом интерфейсе он существенно заморозил все это и вызвал его сбой, хотя без какой-либо конкретной ошибки, показанной на консоли.

Я просмотрел другие способы отправки команд через определенные промежутки времени и наткнулся на Timer поэтому я попытался использовать это. Прямо сейчас у меня есть этот код.

package clock;

import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormAttachment;

public class SystemClock {
    Text labelHours;
    Text labelMinutes;
    Text labelSeconds;
    Text labelMeridian;
    TimerTask time = new TimerTask(){
        public void run(){
            pullClock();
        }
    };
    boolean pause=false;
    Timer play = new Timer();
    long delay = 1000;
    long period = 1000;
    protected Shell shlClock;

    /**
     * Launch the application.
     * @param args
     */
    public static void main(String[] args) {
        try {
            SystemClock window = new SystemClock();
            window.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Open the window.
     */
    public void open() {
        Display display = Display.getDefault();
        createContents();
        shlClock.open();
        shlClock.layout();
        while (!shlClock.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    /**
     * Create contents of the window.
     */
    protected void createContents() {
        shlClock = new Shell();
        shlClock.setSize(205, 118);
        shlClock.setText("Clock");
        shlClock.setLayout(null);

        Label labelColonHoursMinutes = new Label(shlClock, SWT.NONE);
        labelColonHoursMinutes.setBounds(64, 10, 9, 15);
        labelColonHoursMinutes.setText(":");

        Label labelColonMinutesSeconds = new Label(shlClock, SWT.NONE);
        labelColonMinutesSeconds.setBounds(96, 10, 9, 15);
        labelColonMinutesSeconds.setText(":");

        labelMinutes = new Text(shlClock, SWT.NONE | SWT.CENTER);
        labelMinutes.setBounds(71, 10, 19, 15);
        labelMinutes.setEditable(false);
        labelMinutes.setText("00");

        labelHours = new Text(shlClock, SWT.NONE | SWT.CENTER);
        labelHours.setEditable(false);
        labelHours.setBounds(40, 10, 18, 15);
        labelHours.setText("00");

        labelSeconds = new Text(shlClock, SWT.NONE | SWT.CENTER);
        labelSeconds.setBounds(101, 10, 25, 15);
        labelSeconds.setEditable(false);
        labelSeconds.setText("00");

        Button btnRefresh = new Button(shlClock, SWT.NONE);
        btnRefresh.setBounds(58, 36, 75, 25);
        btnRefresh.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                    pause= !pause;
                    if (pause)
                        try{
                            play.scheduleAtFixedRate(time, delay, period);
                        }catch(Exception ex){

                        }
                    else
                        play.cancel();
                }
        });
        btnRefresh.setText("Pause/Play");

        labelMeridian = new Text(shlClock, SWT.NONE);
        labelMeridian.setBounds(125, 10, 25, 15);
        labelMeridian.setEditable(false);
        labelMeridian.setText("AM");

    }


public void pullClock(){
        long currentTime = System.currentTimeMillis();
        int hours;
        int minutes;
        int seconds;
        String hoursStr;
        String minutesStr;
        String secondsStr;
        String meridian;            
            currentTime/=1000;
            seconds = (int)currentTime%60;
            currentTime/=60;
            minutes = (int)currentTime%60;
            currentTime/=60;
            hours = (int)currentTime%24;
            hours -=4;

            switch(hours){
                case -4: hoursStr="8"; meridian = "PM"; break;
                case -3: hoursStr="9"; meridian = "PM"; break;
                case -2: hoursStr="10"; meridian = "PM"; break; 
                case -1: hoursStr="11"; meridian = "PM"; break;
                case  0: hoursStr="12"; meridian = "AM"; break;
                case 12: hoursStr="12"; meridian = "PM"; break;
                case 13: hoursStr="1"; meridian = "PM"; break;
                case 14: hoursStr="2"; meridian = "PM"; break;
                case 15: hoursStr="3"; meridian = "PM"; break;
                case 16: hoursStr="4"; meridian = "PM"; break;
                case 17: hoursStr="5"; meridian = "PM"; break;
                case 18: hoursStr="6"; meridian = "PM"; break;
                case 19: hoursStr="7"; meridian = "PM"; break;
                default: hoursStr=String.valueOf(hours); meridian = "AM";
            }
            secondsStr=String.valueOf(seconds);
            minutesStr=String.valueOf(minutes);
            labelHours.setText(hoursStr);
            labelMinutes.setText((minutes<10) ? "0"+minutesStr:minutesStr);
            labelSeconds.setText((seconds<10) ? "0"+secondsStr:secondsStr);
            labelMeridian.setText(meridian);
        }
    }

Это приводит к org.eclipse.swt.SWTException и org.eclipse.swt.SWTException строя программы.

Я использую Eclipse и легко получаемый редактор SWT gui для создания программы, и, похоже, это часть проблемы. Мой вопрос в основном заключается в том, есть ли способ исправить его, еще используя SWT, и если бы это не сработало, если бы я использовал JFrame?

Теги:
timer
exception
swt

2 ответа

3
Лучший ответ

То, что вы ищете, называется Display#timerExec() в SWT. Метод принимает исполняемый файл, который будет выполняться один раз после того, как пройденное количество миллисекунд.

display.timerExec( 1000, new Runnable() {
  public void run() {
    if( !shlClock.isDisposed() {
      pullClock();
      display.timerExec( 1000, this );
    }
  }
}

В вышеприведенном фрагменте runnable перераспределяет itslef (display.timerExec( 1000, this );), когда была выполнена фактическая работа.

Чтобы отменить уже запланированную runnable, вызовите display.timerExec( -1, runnable ).

  • 0
    Это делает почти то, на что я надеялся. Единственное, что мне еще нужно, - это сделать паузу, если это необходимо. Как бы вы остановились на timerExec, как этот, чтобы он не повторялся бесконечно?
  • 0
    timerExec() выполняет данный runnable только один раз . Бесконечность вызвана runnable, который перепланирует свою часть с display.timerExec( 1000, this ); , Просто пропустите «внутренний» timerExec() чтобы сделать паузу. Смотрите также обновленный ответ.
Показать ещё 1 комментарий
2

Использование display.timerExec как указано в другом ответе, вероятно, лучше всего, но вы также можете использовать Display.syncExec в задаче таймера:

TimerTask time = new TimerTask() {
    public void run() {
        Display.getDefault().synchExec(new Runnable() {
           public void run() {
              pullClock();
           }
        });
    }
};

или если вы используете Java 8, вы можете упростить это как:

TimerTask time = new TimerTask() {
    public void run() {
        Display.getDefault().synchExec(() -> pullClock());
    }
};

Ещё вопросы

Сообщество Overcoder
Наверх
Меню