Java 使用计时器更改用户界面
我试图制作一个每秒更新一次的简单时钟,以降低CPU的成本。我最初尝试使用Thread.sleep,但当在GUI的循环中使用时,它实际上冻结了整个过程并导致崩溃,尽管控制台中没有显示任何特定的错误 我找到了以特定间隔发送命令的其他方法,遇到了计时器,所以我尝试使用它。现在我有这个密码Java 使用计时器更改用户界面,java,eclipse,exception,timer,swt,Java,Eclipse,Exception,Timer,Swt,我试图制作一个每秒更新一次的简单时钟,以降低CPU的成本。我最初尝试使用Thread.sleep,但当在GUI的循环中使用时,它实际上冻结了整个过程并导致崩溃,尽管控制台中没有显示任何特定的错误 我找到了以特定间隔发送命令的其他方法,遇到了计时器,所以我尝试使用它。现在我有这个密码 package clock; import java.util.Timer; import java.util.TimerTask; import org.eclipse.swt.widgets.Display;
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.swt异常并使程序崩溃
我正在使用Eclipse,很容易获得SWTGUI编辑器来构建程序,这似乎是问题的一部分。我的问题本质上是,在仍然使用SWT的情况下,是否有一种方法可以修复它,如果没有,那么如果我使用JFrame,这种方法是否有效?您正在寻找的是SWT中的DisplaytimerExec。该方法接受一个runnable,它将在给定的毫秒数过后执行一次
display.timerExec( 1000, new Runnable() {
public void run() {
if( !shlClock.isDisposed() {
pullClock();
display.timerExec( 1000, this );
}
}
}
在上面的代码段中,runnable重新调度itslef display.timerExec 1000,如下所示;当实际工作完成时
要取消已计划的runnable,请调用display.timerExec-1,runnable。您要查找的是SWT中的DisplaytimerExec。该方法接受一个runnable,它将在给定的毫秒数过后执行一次
display.timerExec( 1000, new Runnable() {
public void run() {
if( !shlClock.isDisposed() {
pullClock();
display.timerExec( 1000, this );
}
}
}
在上面的代码段中,runnable重新调度itslef display.timerExec 1000,如下所示;当实际工作完成时
要取消已计划的runnable,请调用display.timerExec-1,runnable。使用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());
}
};
使用其他答案中提到的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());
}
};
这几乎达到了我的期望。我唯一需要它做的就是在必要时暂停它。您如何像这样暂停timerExec,使其不会无限重复?timerExec只执行一次给定的runnable。无穷大是由runnable使用display.timerExec 1000,this;重新调度itslef造成的;。只需省略“内部”timerExec调用即可暂停。另请参阅更新的答案。谢谢!这正是我想要的。特别是,在已经安排好任务后取消任务的能力。这几乎达到了我的期望。我唯一需要它做的就是在必要时暂停它。您如何像这样暂停timerExec,使其不会无限重复?timerExec只执行一次给定的runnable。无穷大是由runnable使用display.timerExec 1000,this;重新调度itslef造成的;。只需省略“内部”timerExec调用即可暂停。另请参阅更新的答案。谢谢!这正是我想要的。具体地说,是指在已计划任务之后取消该任务的能力。