Anzeige:
Ergebnis 1 bis 6 von 6

Thema: SWT: Fenster nach Ablauf eines Threads erstellen

  1. #1
    Registrierter Benutzer Avatar von neogrande
    Registriert seit
    14.09.2007
    Beiträge
    8

    SWT: Fenster nach Ablauf eines Threads erstellen

    Hallo,

    im Forum sind ja schon sehr viele Einträge zur Änderung eines SWT-Fensters durch einen anderen Thread, was aber nicht mein Problem ist.

    Ich habe ein Hauptfenster, welches ein Thread-Objekt startet (nur mit new Object(), noch kein run() oder start()).
    Dieses Objekt erzeugt ein SWT-Fenster (neue Shell mit Composites...).
    Erst wenn dieses Fenster geschlossen wird, wird der Thread mit start() gestartet und läuft im Hintergrund.
    Nachdem die run()-Methode beendet ist, wird von diesem Objekt ein neues GUI-Objekt erzeugt. Dieses funktioniert leider dank InvalidThreadAccessException nicht.

    Hier mal der Pseudo-Javacode
    Code:
    public ThreadObject extends Thread {
      public ThreadObject() {
        grafik = new Wizard();
      }
    
      public void callIfWizardFinished() {  //wird nach dem Schließen der GUI aufgerufen
        getFactory().ready(); // die Factory ruft dann start() an diesem Objekt auf
      }
    
      public synchronized void run() {
      // hier wird die Arbeit getan
      finishCalculation();
      }
    
      public void finishCalculation() {
         grafik2 = new OtherWizard(); // hier krachts
      }
    }
    Ich ahne bereits, dass es daran liegt, dass finishCalculation noch in run aufgerufen wird, aber irgendwann muss ja mal Schluss sein

    Deswegen habe ich bereits innerhalb meiner Factory den Aufruf von start() ersetzt mit
    Code:
    Display.getCurrent().asyncExec(threadObjectInstance)
    Dies behebt zwar das Problem mit der Erzeugung, sorgt aber dafür, dass mein Hauptfenster während der Berechnung hängt (ich dachte, das soll asyncExec genau verhindern?)

    Grüße

    neogrande

  2. #2
    Registrierter Benutzer Avatar von neogrande
    Registriert seit
    14.09.2007
    Beiträge
    8
    kleiner Nachtrag:

    ich hab die finishedCalculation()-Methode aus dem run() rausgenommen.

    die Factory überprüft jetzt selbstständig auf State.TERMINATED und ruft dann finishedCalculation() auf.

    Leider ist das Ergebnis das selbe, SWT mag wohl auch keine terminierten Threads...

  3. #3
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Also das mit SWT ist bei mir schon ne Weile her (war mal 2003); und das mit syncExec und asyncExec ist irgendwie das was ich immer erfolglos zu erklären versuche (wenn auch hier scheinbar nicht direkt dein Problem)

    Zitat Zitat von neogrande Beitrag anzeigen
    Code:
    Display.getCurrent().asyncExec(threadObjectInstance)
    Dies behebt zwar das Problem mit der Erzeugung, sorgt aber dafür, dass mein Hauptfenster während der Berechnung hängt (ich dachte, das soll asyncExec genau verhindern?)
    Nein. AsyncExec und SyncExec dienen beide dazu, aus einem separat laufenden Thread heraus etwas im Haupt-Gui-verantwortlichen-Thread ausführen zu lassen.

    AsyncExec: Das übergebene Runnable wird in die Nachrichtenverarbeitungsschleife geschmissen. Der Thread der das AsyncExec aufruft läuft direkt weiter.

    SyncExec: AsyncExec: Das übergebene Runnable wird in die Nachrichtenverarbeitungsschleife geschmissen. Der Thread der das SyncExec aufruft wartet bis das Runnable vom Hauptthread ausgeführt wurde und fährt erst dann weiter.

    Das was du hier machst - das aufrufen von SyncExec/AsyncExec aus dem Haupt-Gui-Thread funktioniert zwar scheinbar, ist aber eigentlich nicht der Sinn der Sache.

    So, jetzt aber versuchsweise zu deinem Problem: Ich habe den Durchblick nicht 120%ig gewonnen, darüber was du genau zu machen versuchst; kann also auch falsch liegen.

    Das Problem dass das ganze nicht läuft liegt im kleinen Rahmen daran, wie du richtig erkannt hast, dass SWT das ausführen von Grafikoperation in Threads, die nicht der Haupt-Gui-Thread sind, nicht mag. Genau das versuchst du aber bei
    Code:
         grafik2 = new OtherWizard(); // hier krachts
    Die Lösung liegt in SyncExec/AsyncExec: Verpack deinen grafik2=...-Aufruf in ein Runnable, und gib das via SyncExec/AsyncExec an den Haupt-Gui-Thread rüber, damit der das ausführt (somit macht der die Gui-Operationen, was erlaubt ist).

    Also à la:
    Code:
    new Runnable() {
      void run() {
        grafik2 = new OtherWizard(); 
      }
    }
    etc. an Stelle des direkten Aufrufs

    Dann hast du natürlich evtl. das Problem dass du die Referenz auf das erzeugte Objekt nur innerhalb vom Runnable hast. Was du da machen musst/kannst wenn dich das stört weiss ich aber gerade nicht mehr

    Hat aber afair recht schnell mal ziemlich grosse Auswirkungen auf dein Programmdesign.

    MfG Peschmä
    Geändert von peschmae (14-09-2007 um 16:59 Uhr)
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

  4. #4
    Registrierter Benutzer Avatar von neogrande
    Registriert seit
    14.09.2007
    Beiträge
    8
    Hallo peschmae,

    nach dem durchforsten der anderen Threads war mir klar, dass du antworten würdest , vielen Dank.

    Deine Runnable-Lösung führt erst mal zur Lösung des direkten Problems.

    Dann hast du natürlich evtl. das Problem dass du die Referenz auf das erzeugte Objekt nur innerhalb vom Runnable hast. Was du da machen musst/kannst wenn dich das stört weiss ich aber gerade nicht mehr
    schlecht:
    Code:
    public class ThreadObject {
    
    private static Wizard wizard;
    
    public void startWizard() {
    		Display.getDefault().asyncExec(new Runnable() {
    			public void run() {
    				wizard = new Wizard();
    			}
    		});
    }
    besser: (gut?)
    Code:
    public class ThreadObject {
    
    private Wizard wizard;
    
    public void startWizard() {
    		Display.getDefault().asyncExec(new Runnable() {
    			public void run() {
    				ThreadObject.this.wizard = new Wizard();
    			}
    		});
    }
    Auf jeden Fall kann man dann sehr gut mit dem Wizard arbeiten, muss nur aufpassen, dass man das wizard.start() (was das Fenster anzeigt) auch wieder mittels asyncExec() aufruft. Danach klappen sogar die Wizard-Internen Operationen (wow)

    Hat aber afair recht schnell mal ziemlich grosse Auswirkungen auf dein Programmdesign.
    Allerdings. Zumal diese Aufrufe in einem Programmteil stattfinden, der einfach von anderen Entwicklern erweiterbar sein soll (sie sollen einfach neue ThreadObjekte hinzufügen können). Da macht sich eine so komplizierte Aufruf-Syntax schlecht. Muss ich mir noch gedanken um eine gescheite Kapselung machen.

    Aber dank dir trotzdem, mein Verständnis für SWT und Threads wächst...

  5. #5
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Zitat Zitat von neogrande Beitrag anzeigen
    Auf jeden Fall kann man dann sehr gut mit dem Wizard arbeiten, muss nur aufpassen, dass man das wizard.start() (was das Fenster anzeigt) auch wieder mittels asyncExec() aufruft. Danach klappen sogar die Wizard-Internen Operationen (wow)
    Nett, an das ThreadObject konnte ich mich nicht mehr erinnern

    Da macht sich eine so komplizierte Aufruf-Syntax schlecht. Muss ich mir noch gedanken um eine gescheite Kapselung machen.
    Ja, das ist dann schlussendlich das grosse Problem - immer wenn du was Gui-Mässiges ausm Thread machen willst wirds ein Fünfzeiler

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

  6. #6
    Registrierter Benutzer Avatar von neogrande
    Registriert seit
    14.09.2007
    Beiträge
    8
    Moin ,

    was hälst du hiervon:

    Code:
    innerhalb von Wizard:
    
    private static Wizard instanceForAsyncCreation;
    
    public static Wizard giveStartedInstance(Class clazz) {
      instanceForAsyncCreation = null;
    			
      if (!isWizard(clazz)) { // möchte nur von Wizard abgeleitete Klassen haben...
        return null;
      }
    				
    			
      Display.getDefault().asyncExec(new Runnable() {
        public void run() {
          Wizard.instanceForAsyncCreation = (Wizard) clazz.newInstance(); // try-catch mal wegen Übersichtlichkeit weggelassen
          Wizard.instanceForAsyncCreation.start();
        }
      });
    
      return instanceForAsyncCreation;
    }
    dann müsste man im ThreadObject nur noch aufrufen:
    Code:
    Wizard wizard = (WizardChild)
      Wizard.giveStartedInstance(WizardChild.class, this);
    da hab ich nun doch wieder meine static Instanz und bin mir nicht sicher, ob das noch kompatibel mit $(good_architecture) ist

    Aber es funktioniert

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •