小编典典

定期更新SWT会导致GUI冻结

java

问题 :定期更新GUI字段时,SWT冻结。

我想有一个带有文本字段的基于SWT的GUI,其值会定期增加。

  1. 最初,我从单独的线程访问textField导致抛出异常:

线程“
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)

  1. 阅读SWT文档(由于@ marko-topolnik)之后,我尝试在循环中使用display.SyncExec(Runnable r)display.AsyncExec(Runnable r)与runnable一起使用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);
}

}

如何避免冻结和引发异常?


阅读 202

收藏
2020-12-03

共1个答案

小编典典

任何更改UI对象的SWT操作都必须在SWT用户界面线程上运行。

在您的情况下,该text.setText(i.toString());行是SWT UI操作,并且在其他线程中运行。

您可以使用的asyncExecsyncExec方法Display在UI线程中运行一些代码。因此,请替换:

text.setText(i.toString());

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也是错误的。该线程有效:

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();
2020-12-03