使用计时器更改UI

时间:2015-03-20 03:40:40

标签: java eclipse exception timer swt

我试图制作一个每秒更新一次的简单时钟,以降低CPU的成本。我最初尝试使用Thread.sleep(),但是当在GUI中的循环中使用时,它基本上冻结了整个事物并导致它崩溃,但没有在控制台中显示任何特定错误。

我查找了其他方式以特定间隔发送命令并遇到了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并导致程序崩溃。

我正在使用Eclipse,它很容易获得SWT gui编辑器来构建程序,它似乎是问题的一部分。我的问题基本上是,如果有一种方法可以在使用SWT时修复它,如果不是,那么如果我使用JFrame会这样吗?

2 个答案:

答案 0 :(得分:3)

您正在寻找的内容在SWT中称为Display#timerExec()。该方法接受一个runnable,它将在经过一定量的毫秒后执行一次。

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 )

答案 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());
    }
};