从另一个线程更新SWT对象

Mri*_*lla 15 java swt

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

我在网上找到了一些例子,但它们都涉及GUI在主线程中运行的情况,而长操作则在单独的线程中.我的情况完全相反.

有人能告诉我如何更新GUI线程中的小部件吗?

Rid*_*del 33

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

Display.getDefault().asyncExec(new Runnable() {
    public void run() {
        someSwtLabel.setText("Complete!");
    }
});
Run Code Online (Sandbox Code Playgroud)

对于更长的解释,这篇JavaLobby文章是对这种线程使用模型的一个很好的介绍.

  • 如果需要,您还可以使用syncExec获取同步更新.但我也加入其他人,说你的问题不同 - 你正在访问一个空引用.尝试在非ui线程中调用某些SWT方法时会遇到不同的异常(无效的线程访问或类似的东西) (2认同)

Fav*_*ius 7

我认为你得到的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);
            }
        });

    }

}
Run Code Online (Sandbox Code Playgroud)

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

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

在这样的场景中你必须有效地使用waityield方法...否则会导致"难以找到错误"...即等待UI正确实例化然后产生...

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

希望这会通过你的问题的一些亮点....