【问题标题】:Updating SWT objects from another thread从另一个线程更新 SWT 对象
【发布时间】:2010-12-07 02:17:29
【问题描述】:

在我的 Java 应用程序中,当调用主模块时,我在一个单独的线程中启动我的 SWT GUI。我需要在主线程中执行一些长时间的操作并更新 GUI 线程。当我尝试从主线程更新 GUI 线程时,即更改标签文本或其他内容时,我得到一个 java.lang.NullPointerException。从我在线阅读的内容来看,是因为 SWT 不允许非 UI 线程更新 UI 对象。如何从主线程更新 GUI 线程。

我在网上找到了一些示例,但它们都处理 GUI 在主线程中运行并且长时间操作在单独线程中的场景。我的情况完全相反。

谁能告诉我如何在 GUI 线程中更新小部件?

【问题讨论】:

  • 当您从错误的线程更新某些 GUI 组件时,通常不会收到 NullPointerException。你确定这是线程问题吗?

标签: java swt


【解决方案1】:

简而言之,SWT 是一个单线程 UI 工具包。因此,小部件必须在 SWT 事件线程中更新,就像在 Swing 中一样。因此,您必须使用匿名 Runnable 类调用刷新:

Display.getDefault().asyncExec(new Runnable() {
    public void run() {
        someSwtLabel.setText("Complete!");
    }
});

为了更详细的解释,这篇JavaLobby 文章很好地介绍了这种线程使用模型。

【讨论】:

  • 如果需要,您还可以使用 syncExec 获取同步更新。但我也加入了其他人的行列,说你的问题是不同的——你正在访问一个空引用。尝试在非 ui 线程中调用某些 SWT 方法(无效的线程访问或类似的东西)时,您会得到一个不同的异常
  • 如果您想在本地线程中使用 JNI Invocation API 调用方法更新 UI,有什么技巧吗?即使后台线程不调用任何 java 方法,我得到的只是一个锁定的 UI。如果我尝试 (a)syncExec 效果保持不变。锁定用户界面...
【解决方案2】:

我认为您收到java.lang.NullPointerException 是因为您试图在创建 GUI 组件之前访问它。理想情况下,您应该等待创建 gui 组件...例如...

我在一个单独的线程中创建一个单一的 GUI...像这样

package test;


import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class GUIThread implements Runnable 
{
    private Display display;
    private Label label;
    public Display getDisplay(){
        return display;
    }
    public void run() 
    {
        display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new GridLayout());
        shell.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,false));
        label = new Label(shell,SWT.NONE);
        label.setText(" -- ");
        shell.open();
        shell.pack();

        while (!shell.isDisposed()) {
        if (!display.readAndDispatch ()) display.sleep ();
        }
        display.dispose();
    }

    public synchronized void update(final int value)
    {
        if (display == null || display.isDisposed()) 
            return;
        display.asyncExec(new Runnable() {

            public void run() {
                label.setText(""+value);
            }
        });

    }

}

在我的主要方法中,我做了这样的事情......

package test;

import org.eclipse.swt.widgets.Display;

public class Main 
{

    public static void main(String[] args) throws Exception
    {
        final GUIThread gui = new GUIThread();
        Thread t = new Thread(gui);
        t.start();

        Thread.sleep(3000); // POINT OF FOCUS
        Display d = gui.getDisplay();

        for(int i = 0; i<100; i++)
        {           
            System.out.println(i + "  " + d);
            gui.update(i);  
            Thread.sleep(500);
        }
    }
}

现在如果我们在上面的代码中注释掉POINT OF FOCUS,那么我总是会得到NullPointerException...但是3秒的延迟让我的GUI线程有足够的时间进入就绪状态,因此它不会通过NullPointerException.....

在这种情况下,您必须有效地使用 waityield 方法...否则会导致“很难找到错误”...即等待 UI 正确实例化然后屈服... .

另外,实际处理是在主线程中完成的,GUI 是在单独的线程中运行的……为了正确通信,最好有一些共享和同步的数据结构……或者可以使用套接字通信来完成……您的主线程填充了一些 port 和您的 GUI 线程 asynchronously 在该端口上侦听......

希望这可以解决您的问题....

【讨论】:

  • 嗨,法沃纽斯。 NullPointerException 正是由您所说的引起的。您的回答帮助我解决了这两个问题——更新 GUI 并摆脱了该错误。谢谢。
猜你喜欢
  • 1970-01-01
  • 2010-11-22
  • 2017-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-13
  • 2023-03-29
相关资源
最近更新 更多