Обновление объектов SWT из другого потока - PullRequest
15 голосов
/ 06 декабря 2010

В моем приложении Java, когда вызывается основной модуль, я запускаю свой SWT GUI в отдельном потоке.Мне нужно выполнить несколько длинных операций в основном потоке и обновить поток GUI.Когда я пытаюсь обновить поток GUI из основного потока, т.е. изменить текст метки или что-то, я получаю java.lang.NullPointerException.Из того, что я прочитал в Интернете, является то, что SWT не позволяет потокам, не являющимся пользовательским интерфейсом, обновлять объекты пользовательского интерфейса.Как я могу обновить поток GUI из основного потока.

Я нашел несколько примеров в Интернете, но все они имеют дело со сценарием, в котором графический интерфейс запускается в основном потоке, а длительная операция - в отдельном потоке.Мой сценарий полностью противоположен.

Может кто-нибудь сказать мне, как я могу обновить виджеты в потоке GUI?

Ответы [ 2 ]

33 голосов
/ 06 декабря 2010

Короче говоря, SWT - это однопоточный инструментарий пользовательского интерфейса.Как следствие, виджеты должны обновляться в потоке событий SWT, как в Swing.Таким образом, вам придется вызывать обновление, используя анонимные Runnable классы:

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

Для более подробного объяснения эта статья JavaLobby является хорошим введением в эту модель использования потоков.

7 голосов
/ 06 декабря 2010

Я думаю, что вы получаете java.lang.NullPointerException, потому что вы пытаетесь получить доступ к компоненту 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 .....

В подобном сценарии вы должны эффективно использовать wait и yieldметоды ... в противном случае это приведет к "Трудно найти ошибки" ... то есть ждать, пока пользовательский интерфейс будет правильно создан, а затем привести к ...

Также фактическая обработка выполняется в основном потоке, и графический интерфейс выполняетсяв отдельном потоке ... для правильной связи хорошо иметь некоторую общую и синхронизированную структуру данных ... или это можно сделать с помощью сокетной связи ... ваш основной поток заполняет некоторую port и ваш поток GUI asynchronously прослушиваетна этом порту ....

Надеюсь тЕго воля проливает свет на вашу проблему ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...