15 Stimmen

SWT-Objekte von einem anderen Thread aus aktualisieren

In meiner Java-Anwendung, wenn das Hauptmodul aufgerufen wird, starte ich meine SWT-GUI in einem separaten Thread. Ich muss einige lange Operationen im Hauptthread durchführen und den GUI-Thread aktualisieren. Wenn ich versuche, den GUI-Thread vom Haupt-Thread aus zu aktualisieren, d. h. einen Beschriftungstext oder etwas anderes zu ändern, erhalte ich eine java.lang.NullPointerException . Von dem, was ich online gelesen habe, ist, weil SWT nicht zulässt, dass Nicht-UI-Threads UI-Objekte zu aktualisieren. Wie kann ich den GUI-Thread aus dem Hauptthread aktualisieren.

Ich habe einige Beispiele im Internet gefunden, aber sie beziehen sich alle auf ein Szenario, bei dem die grafische Benutzeroberfläche im Haupt-Thread läuft und lange Operationen in einem separaten Thread ausgeführt werden. Mein Szenario ist das genaue Gegenteil.

Kann mir jemand sagen, wie ich Widgets im GUI-Thread aktualisieren kann?

33voto

Riduidel Punkte 21566

Um es kurz zu machen: SWT ist ein Single-Thread-UI-Toolkit. Infolgedessen müssen Widgets im SWT-Ereignis-Thread aktualisiert werden, wie in Swing. Daher müssen Sie die Aktualisierung mit anonymen Runnable Klassen:

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

Eine längere Erklärung finden Sie hier JavaLobby Artikel ist eine gute Einführung in dieses Threading-Nutzungsmodell.

8voto

Favonius Punkte 13720

Ich glaube, Sie bekommen java.lang.NullPointerException weil Sie versuchen, auf die GUI-Komponente zuzugreifen, bevor sie erstellt wurde. Idealerweise sollten Sie warten, bis die GUI-Komponente erstellt wurde... zum Beispiel...

Ich erstelle eine einzelne GUI in einem separaten Thread... etwa so

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

    }

}

Und in meiner Hauptmethode mache ich etwas wie dies....

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

Wenn wir nun die POINT OF FOCUS im obigen Code, dann erhalte ich immer NullPointerException ... Aber eine Verzögerung von 3 Sekunden gibt meinem GUI-Thread genug Zeit, um in den Bereitschaftszustand zu gelangen, und daher wird er nicht durch NullPointerException .....

In einem solchen Szenario müssen Sie die wait y yield Methoden... andernfalls würde es zu "Hard to find Bugs" führen... d.h. warten, bis die UI richtig instanziiert ist und dann nachgeben...

Auch die eigentliche Verarbeitung erfolgt im Haupt-Thread und die GUI läuft in einem separaten Thread... um richtig zu kommunizieren, ist es gut, eine gemeinsam genutzte und synchronisierte Datenstruktur zu haben... oder es könnte mit Hilfe von Socket-Kommunikation erfolgen... Ihr Haupt-Thread befüllt einige port und Ihr GUI-Thread asynchronously auf diesem Port hören....

Ich hoffe, dies bringt etwas Licht in Ihr Problem....

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X