2010-12-06 13 views
15

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 zu aktualisieren, d. H. Einen Etikettentext oder etwas anderes zu ändern, erhalte ich eine java.lang.NullPointerException. Von dem, was ich online gelesen habe, ist, weil SWT Nicht-UI-Threads nicht erlaubt, UI-Objekte zu aktualisieren. Wie kann ich den GUI-Thread vom Haupt-Thread aktualisieren?Aktualisieren von SWT-Objekten von einem anderen Thread

Ich habe einige Beispiele online gefunden, aber sie alle befassen sich mit dem Szenario, in dem die GUI im Hauptthread läuft und lange Operation in separaten Thread ist. Mein Szenario ist das Gegenteil.

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

+0

Im Allgemeinen erhalten Sie nicht eine 'NullPointerException', wenn Sie einige GUI-Komponente aus dem falschen Thread aktualisieren. Sind Sie wirklich sicher, dass es sich um ein Threading-Problem handelt? – Flavio

Antwort

7

Ich denke, Sie erhalten java.lang.NullPointerException, weil Sie versuchen, auf die GUI-Komponente zuzugreifen, bevor es erstellt wird. Im Idealfall sollten Sie für die GUI-Komponente warten erstellt bekommen ... zum Beispiel ...

ich eine einzige GUI in einem separaten Thread erstellen ... wie diese

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 Haupt-Methode i so etwas tun ....

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

Nun, wenn wir die POINT OF FOCUS in dem obigen Code kommentieren Sie dann werde ich immer NullPointerException ... aber eine Verzögerung von 3 Sekunden gibt meinem GUI-Thread genügend Zeit, um in zu sein Bereit Zustand und daher nicht durch NullPointerException .....

In einem solchen Szenario müssen Sie die Methoden wait und yield effizient verwenden ... sonst würde es zu "Schwer zu findenden Bugs" kommen ... dh warten, bis die Benutzeroberfläche ordnungsgemäß instanziiert wurde Ausbeute ...

Auch die eigentliche Verarbeitung erfolgt im Haupt-Thread und GUI läuft in separaten Thread ... um richtig zu kommunizieren ist es gut, einige gemeinsame und synchronisierte Datenstruktur zu haben ... oder es könnte getan werden mit Socket-Kommunikation ... Ihr Haupt-Thread bevölkern einige port und Ihre GUI-Thread asynchronously hören auf diesem Port ....

Hoffe, dass dies Throug h ein wenig Licht auf Ihr Problem ....

+0

Hallo Favonius.Die 'NullPointerException' wurde durch genau das verursacht, was Sie sagten. Sie haben mir geholfen, beide Probleme zu beheben - die GUI zu aktualisieren und diesen Fehler loszuwerden. Vielen Dank. –

32

Kurz gesagt, SWT ist ein single-threaded UI-Toolkit. Folglich müssen Widgets im SWT-Ereignis-Thread aktualisiert werden, wie in Swing. So werden, müssen Sie die Refresh mit einem anonymen Runnable Klassen nennen:

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

Für eine längere Erklärung, diese JavaLobby Artikel ist eine gute Einführung in dieses Einfädeln Nutzungsmodell.

+2

Sie können auch syncExec verwenden, um bei Bedarf ein synchrones Update zu erhalten. Aber ich schließe mich den anderen an und sage, dass Ihr Problem anders ist - Sie greifen auf eine Nullreferenz zu. Sie erhalten eine andere Ausnahme, wenn Sie versuchen, eine SWT-Methode in einem Nicht-ui-Thread aufzurufen (Ungültiger Thread-Zugriff oder so) – duduamar

+1

Alle Tricks, wenn Sie die Benutzeroberfläche mit Aufrufmethoden von JNI Invocation API in einem nativen Thread aktualisieren möchten ? Alles, was ich bekomme, ist eine gesperrte Benutzeroberfläche, selbst wenn der Backing-Thread keine Java-Methoden aufruft. Wenn ich (a) syncExec versuche, bleibt der Effekt gleich. A Locking UI ... – kneo

Verwandte Themen