问题 :定期更新GUI字段时,SWT冻结。
我想有一个带有文本字段的基于SWT的GUI,其值会定期增加。
线程“ Thread-0”中的异常org.eclipse.swt.SWTException:在org.eclipse.swt.SWT.error(SWT.java)的org.eclipse.swt.SWT.error(SWT.java:4533)处无效的线程访问:4448),位于org.eclipse.swt.SWT.error(SWT.java:4419),位于org.eclipse.swt.widgets.Widget.error(Widget.java:482),位于org.eclipse.swt.widgets.Widget。在org.eclipse.swt.widgets.Text.setText(Text.java:2311)在regreon处检查Widget(Widget.java:373)在java.lang.Thread.run(0在Incrementing.lambda $ 0(Incrementing.java:62)线程(java:745)
display.SyncExec(Runnable r)
display.AsyncExec(Runnable r)
Thread.sleep
包装任何东西;导入org.eclipse.swt.widgets.Display; 导入org.eclipse.swt.widgets.Shell; 导入org.eclipse.swt.widgets.Text; 导入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); }
}
如何避免冻结和引发异常?
任何更改UI对象的SWT操作都必须在SWT用户界面线程上运行。
在您的情况下,该text.setText(i.toString());行是SWT UI操作,并且在其他线程中运行。
text.setText(i.toString());
您可以使用的asyncExec或syncExec方法Display在UI线程中运行一些代码。因此,请替换:
asyncExec
syncExec
Display
与
final String newText = i.toString(); Display.getDefault().asyncExec(() -> text.setText(newText));
(这是假设您使用的是Java 8)。
使用asyncExec将异步进行UI更新。syncExec如果您想暂停线程直到更新完成,请改用。
如果您使用的是Java 7或更早版本,请使用:
final String newText = i.toString(); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { text.setText(newText); } });
请注意,您还应该检查是否Shell正在处理该线程并停止后台线程。如果不这样做,则在关闭应用程序时会出现错误。您的代码增量i也是错误的。该线程有效:
Shell
i
new Thread(() -> { for (int i = 1; true; i++) { try { Thread.sleep(1000); } catch (final InterruptedException e) { return; } if (shell.isDisposed()) // Stop thread when shell is closed break; final String newText = Integer.toString(i); Display.getDefault().asyncExec(() -> text.setText(newText)); } }).start();