PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [SWT] Thread legt Display lahm



Technaton
12-05-2005, 16:27
Hallo,

ich habe in einen Composite-Container eine Progressbar eingepflanzt. Damit die, während sie fortlaufend aktualisiert wird, nicht das ganze Programm lahmlegt, habe ich die Methode, die den Status der Progressbar setzt, in ein display.asyncExec(Runnable) gepackt.

Das Ergebnis ist jetzt, daß nicht, wie vorher, mein Dialogfeld erst dann erscheint, wenn die Progressbar bei 100% angelangt ist, ein Teilziel also erreicht.
In gewisser Weise ist das Dialogfeld aber trotzdem blockiert: Die Schaltfläche zum Abbrechen nimmt keine Events entgegen, die werden sozusagen aufgespart und dann am Ende des Progressbarthreads ausgeführt.

Da die Dialogfelder alle sehr ähnlich sehen, kommen sie aus einer von mir gebastelten Factory, das Event, das den Klick auf "Abbrechen" auffängt, ist also schon komplett implementiert, wenn der Thread gestartet wird...

Jemand eine Idee, wie ich die Events auch entgegennehmen kann, wenn der Thread, der die Progressbar aktualisiert, gerade läuft?

Gruß,
Techl

peschmae
12-05-2005, 17:45
Was ist denn in dem runnable alles drin? Jetzt so blind geraten machst du denselben Denkfehler wie jemand anderes hier vor etwa einer Woche: das Asyncexec-Zeugs wird im Hauptthread ausgeführt.
Entsprechend tust du gut daran in dem Runnable _nur_ den Aufruf zum setzen des Status reinzutun und sonst überhaupt nichts (und vor allem keine wartende Schleife).

MfG Peschmä

Technaton
12-05-2005, 19:47
In dem Runnable für die Progressbar ist folgender Code drin (ist nur ein kleiner Test, später kommt da eine andere Schleife rein):


for(int i=0;i<200;++i) {
try {
Thread.sleep(10);
progressbar.setLocation(i);
} catch(Exception e) {
e.printStackTrace();
}
}

Der Rest ist außerhalb definiert. Jemand hat mir mittlerweile den Tipp gegeben, auch den "Main Event Loop" des SWT in einen Thread zu packen, aber ich habe nicht ganz verstanden, was die Person meinte, denn was ich daraus gemacht habe, funktioniert nicht ;) Folgendes habe ich nämlich in die run() einer anderen Klasse gepackt:

while(!shell.isDisposed()) if(!display.readAndDispatch() display.sleep();

Soweit ich das nachvollziehen kann, besteht mein Fehler aber nur darin, nicht das richtige in den neuen Thread zu packen. Um alle Fehler auszuschließen will ich das Konstrukt beschreiben, das mir jetzt vorschwebt: Das eigentliche Programm, das bei mir bisher ohne irgendwelchen zusätzlichen Threadkram lief, kommt in einen Thread (inklusive thread.sleep(), damit das sich Programm nicht beendet, usw, also ein neuer, voller Thread eben); und innerhalb dieses Thread starte ich mit display.asyncExec() einen neuen Thread, der dann nebenherläuft.

Ist das richtig gedacht und nur falsch umgesetzt oder schon falsch gedacht? :)

P.S.: Ich habe den Thread, von den du erwähntest, nicht gefunden; welchen Titel trägt der?

peschmae
12-05-2005, 20:28
Da isser: http://www.mrunix.de/forums/showthread.php?t=39112


In dem Runnable für die Progressbar ist folgender Code drin (ist nur ein kleiner Test, später kommt da eine andere Schleife rein):


for(int i=0;i<200;++i) {
try {
Thread.sleep(10);
progressbar.setLocation(i);
} catch(Exception e) {
e.printStackTrace();
}
}

Du solltest den Code so ändern dass *nur* der progressbar.setLocation(i) aufruf in dem Runnable ist, das du asyncExec übergibst. Sonst nichts.

Wieso? Das Runnable, welches du AsyncExec übergibst wird bei der nächsten Gelegenheit ausgeführt - aber nicht als eigener Thread (wie wenn du das mit start() gestartet hättest, oder wie die Methoden schon wieder heissen) - sondern es wird einfach die run()-Methode in der Nachrichtenschleife im Hauptthread ausgeführt.
Also genau wie wenn du die Schleife im Hauptthread hättest. Das ist genau das was du nicht willst - denn dadurch dass die Nachrichtenschleife jetzt damit beschäftigt ist dein Runnable auszuführen kann sie in der Zwischenzeit keine anderen Events bearbeiten...


... innerhalb dieses Thread starte ich mit display.asyncExec() einen neuen Thread, der dann nebenherläuft.

Display.asyncExec() führt - wie schon gesagt keinen neuen Thread aus. Vielmehr wird das übergeben Runnable eben gerade nicht in einem eigenen sondern im Hauptthread ausgeführt.
Das ist nötig um aus separat laufenden Threads auf GUI-Elemente zugreifen zu können.

MfG Peschmä

Technaton
12-05-2005, 21:01
Hab mir die Sache angesehen, und es funktioniert, danke dir! *freu* Hast wieder einen Menschen glücklich gemacht :)

Noch ne Kleinigkeit: Gibt's was eleganteres als

final int i2 = i;, um innerhalb des Threads auf die Zählvariable zugreifen zu können?

peschmae
12-05-2005, 21:32
Wieso ist denn das nötig?

MfG Peschmä

Technaton
12-05-2005, 23:13
Ich habe den Thread ja jetzt, wie empfohlen, IN die Schleife gesetzt, und das funktioniert auch. Aber wenn ich von im Thread auf die Zählervariable zugreifen muß, bekomme ich die Fehlermeldung, daß ich nicht auf nicht-finale Variablen zugreifen kann -- das kommt wohl daher, daß ich den asyncExec-Aufruf in eine anonyme Klasse packe. Aber ich weiß nicht, wie ich den Thread in eine benannte packen kann, ohne diese SWT-Exception "Invalid Thread access" zu erhalten.

peschmae
13-05-2005, 07:30
Achja, stimmt. Ist halt schon etwas her das ich das benutzt habe ;)

Eventuell gehts besser wenn du die entsprechende Variable private aber als Member der Klasse machst oder so?

Naja, wobei, das ist alles nicht soo schön.

Eine andere Möglichkeit wäre z.B. dem runnable (das ist kein Thread!) eine seti(int i) Methode mitzugeben die du dann vorher aufrufst um das I zu setzen.

MfG Peschmä

Technaton
13-05-2005, 11:58
Dann sag ich doch mal Dankeschön! :)