问题:当GUI字段定期更新时,SWT会冻结。
我希望有一个带文本字段的基于SWT的GUI,值会定期递增。
线程中的异常"线程0" org.eclipse.swt.SWTException:无效 在org.eclipse.swt.SWT.error(SWT.java:4533)的线程访问 org.eclipse.swt.SWT.error(SWT.java:4448)at org.eclipse.swt.SWT.error(SWT.java:4419)at org.eclipse.swt.widgets.Widget.error(Widget.java:482)at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:373)at org.eclipse.swt.widgets.Text.setText(Text.java:2311)at regreon.Incrementing.lambda $ 0(Incrementing.java:62)at java.lang.Thread.run(Thread.java:745)
阅读SWT文档后(感谢@ marko-topolnik) - 我尝试使用display.SyncExec(Runnable r)
或display.AsyncExec(Runnable r)
在循环中使用名为Thread.sleep
的runnable。但这导致整个事情冻结。
这是代码:
打包什么; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.SWT;
公共类FreezingGUI {protected Shell shell;
private Text text;
public static void main(String[] args) {
try {
FreezingGUI window = new FreezingGUI();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
// HOW TO DO THAT???
display.syncExec(() -> {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Integer i = Integer.parseInt(text.getText()) + 1;
text.setText(i.toString());
}
}
}
);
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
protected void createContents() {
shell = new Shell();
shell.setSize(450, 300);
shell.setText("SWT Application");
text = new Text(shell, SWT.BORDER);
text.setEditable(false);
text.setText("0");
text.setBounds(30, 32, 78, 26);
}
}
如何避免冻结和抛出异常?
答案 0 :(得分:2)
任何更改UI对象的SWT操作都必须在SWT用户界面线程上运行。
在您的情况下,text.setText(i.toString());
行是SWT UI操作,并且正在另一个线程中运行。
您可以使用asyncExec
的{{1}}或syncExec
方法在UI线程中运行一些代码。所以替换:
Display
带
text.setText(i.toString());
(假设您使用的是Java 8)。
使用final String newText = i.toString();
Display.getDefault().asyncExec(() -> text.setText(newText));
将异步进行UI更新。如果要在更新完成之前暂停线程,请使用asyncExec
。
如果您使用的是Java 7或更早版本,请使用:
syncExec
请注意,您还应该检查正在处理的 final String newText = i.toString();
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
text.setText(newText);
}
});
并停止后台主题。如果您不这样做,您将在关闭应用程序时收到错误消息。您的代码递增Shell
也是错误的。这个线程有效:
i
答案 1 :(得分:0)
看看您的代码,您的UI冻结的原因是因为您正在Display.sync上执行一个可运行的内容,由于while(true)循环,该内容永远不会返回,因此,其他UI线程没有机会执行,UI冻结。您需要做的是使用Displasy.asyncRunnable,而不是使用while(true)来创建可运行程序,而不是使调度程序或另一个线程每隔x秒休眠一次,执行该可运行程序以进行所需的更新,这样其他UI线程可以运行以防止UI冻结。