定期更新SWT会导致GUI冻结 [英] Updating SWT periodically causes GUI to freeze

查看:58
本文介绍了定期更新SWT会导致GUI冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Problem: SWT freezes when GUI field is periodically updated.

我希望有一个带有文本字段且值会定期递增的基于SWT的GUI.

I would like to have a SWT-based GUI with text field were values are periodically incremented.

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

线程"Thread-0"中的异常org.eclipse.swt.SWTException:无效 org.eclipse.swt.SWT.error(SWT.java:4533)处的线程访问 org.eclipse.swt.SWT.error(SWT.java:4448)在 org.eclipse.swt.SWT.error(SWT.java:4419)在 org.eclipse.swt.widgets.Widget.error(Widget.java:482)在 org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:373)在 org.eclipse.swt.widgets.Text.setText(Text.java:2311)在 regreon.Incrementing.lambda $ 0(Incrementing.java:62)在 java.lang.Thread.run(Thread.java:745)

Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid thread access at org.eclipse.swt.SWT.error(SWT.java:4533) at 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)

  1. 在阅读了SWT文档之后(由于@ marko-topolnik)-我尝试在循环中使用display.SyncExec(Runnable r)display.AsyncExec(Runnable r)并使用名为Thread.sleep的运行库.但这导致整个事物冻结. 这是代码:

  1. After reading SWT documentation (thanks to @marko-topolnik ) - I tried using display.SyncExec(Runnable r) or display.AsyncExec(Runnable r) with runnable that called Thread.sleep in the loop. But this caused the whole thing to freeze. Here is the code:

打包任何东西; 导入org.eclipse.swt.widgets.Display; 导入org.eclipse.swt.widgets.Shell; 导入org.eclipse.swt.widgets.Text; 导入org.eclipse.swt.SWT;

package whatever; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.SWT;

公共类FreezingGUI {

public class 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);
}

}

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

How to avoid freezing and throwing exception?

推荐答案

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

Any SWT operation which changes a UI object must be run on the SWT User Interface thread.

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

In your case the text.setText(i.toString()); line is an SWT UI operation and is running in a different thread.

您可以使用DisplayasyncExecsyncExec方法在UI线程中运行一些代码.因此,替换:

You can use the asyncExec or syncExec methods of Display to run some code in the UI thread. So replace:

text.setText(i.toString());

final String newText = i.toString();
Display.getDefault().asyncExec(() -> text.setText(newText));

(假设您使用的是Java 8).

(this is assuming you are using Java 8).

使用asyncExec将异步进行UI更新.如果要暂停线程直到更新完成,请使用syncExec.

Using asyncExec will do the UI update asynchronously. Use syncExec instead if you want to pause the thread until the update is done.

如果您使用的是Java 7或更早版本,请使用:

If you are using Java 7 or earlier use:

 final String newText = i.toString();
 Display.getDefault().asyncExec(new Runnable() {
    @Override
    public void run() {
      text.setText(newText);
    }
 });

请注意,您还应该检查是否正在处置Shell并停止后台线程.如果不这样做,则在关闭应用程序时会出现错误.您的代码递增i也是错误的.该线程有效:

Note you should also be checking for the Shell being disposed and stopping your background thread. If you don't do this you will get an error when you close the app. Your code incrementing i is also wrong. This thread works:

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();

这篇关于定期更新SWT会导致GUI冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆