使用计时器改变 UI
Use timers to change UI
我试图制作一个每秒更新一次的简单时钟,以降低 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
?
您要查找的内容在 SWT 中称为 Display#timerExec()
。该方法接受一个可运行对象,它将在经过给定的毫秒数后执行一次。
display.timerExec( 1000, new Runnable() {
public void run() {
if( !shlClock.isDisposed() {
pullClock();
display.timerExec( 1000, this );
}
}
}
在上面的代码片段中,当实际工作完成时,runnable 会重新安排 itslef (display.timerExec( 1000, this );
)。
为了取消已经安排好的运行,调用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());
}
};
我试图制作一个每秒更新一次的简单时钟,以降低 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
?
您要查找的内容在 SWT 中称为 Display#timerExec()
。该方法接受一个可运行对象,它将在经过给定的毫秒数后执行一次。
display.timerExec( 1000, new Runnable() {
public void run() {
if( !shlClock.isDisposed() {
pullClock();
display.timerExec( 1000, this );
}
}
}
在上面的代码片段中,当实际工作完成时,runnable 会重新安排 itslef (display.timerExec( 1000, this );
)。
为了取消已经安排好的运行,调用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());
}
};