# SWT und Listener



## Koringar (16. Mrz 2009)

Guten Tag,

da ich fast das ganz google durchforstet habe und immer noch nichts gefunden habe stell ich meine Frage mal hier.
Ich suche ein Tutorial zu Listener in SWT, zwar was eins dass beschreibt wie man ein Listener selbst macht. Mit den vorhandenen kenne ich mich schon aus und sie bieten nicht das was ich will, also wollt ich selber einen schreiben.
Es gibt zwar haufen Tutorials zu Listenener, die sind aber bis jetzt alle in Verbindung mit Swing gewesen (leider).

Oder wenn mir einer genauer helfen kann, da ich noch so ziemlicher SWT Neuling bin.
Ich will einen Chat in Java programmieren oder eher habe es schon unter Swing und jetzt wollt ich das mal so Spaßeshalber und um SWT besser kennen zulernen das mal unter SWT nachprogrammieren.
Ich habe eine GUI an dem ein StyleText als Ausgabe des Netzwerkverkehrs und paar Tables und Lists hängen. Über einen Thread starte ich eine Art Listener (benonnung auf Art) die auf den Socket horcht und wartet bis eine Nachricht kommt oder eben bis zum TimeOut. Und wenn ich die Nachricht jetzt weitergeben will und auswerten gibt es immer ein 'Invalid Thread Access' als fehler, da man außerhalb des Shell-Thread nicht auf die GUI zugreifen darf. Ich habe es schon mit des syncExec und asyncExec probiert, aber das hat auch nicht gebracht da dieser Thread zum horchen aufs Netz eine Endlosschleife ist bis der ganze Server oder Client geschlossen wird, als 'hängert' er sich auf.
Nun habe ich durch Google raus gefunden das man das gut über Listener machen könnte, habe dazu aber in Verbindung mit SWT nichts gefunden oder nichts aussagekräftiges.

Wäre schön wenn einer Helfen könnte, als Anforderungen für den Listener sollen sein:
Das er auf den Socket horcht ob eine Nachricht ein trifft, wenn dies der Fall ist dann soll er ein Event auslösen das der Shell mitteilt das eine Nachricht da ist und sie übergibt, damit sie von der Shell verarbeitet werden kann.

Vielen Dank schon mal für die Mühe.

MFG


----------



## tuxedo (16. Mrz 2009)

Listener hin oder her: Du musst die Thread-Sperre durchbrechen.
Mit Listener alleine wüsste ich nicht wie man das bewerkstelligen kann. 

Ganz naiv könnte man es so entkoppeln:

Der Netzwerkthread schreibt seine Daten in eine Liste. Und damit diese dann in die GUI wandern können, muss der Netzwerkthread asyncExec() auf dem Display aufrufen. Das Runnable das du da übergibst holt sich dann die Daten aus der Liste und zeigt sie in der GUI an.

Kurz gesagt: im asyncExec-Runnable darf nur das erledigt werden was die GUI betrifft. Also nix mit aufm Netzwerk lauschen oder Daten verarbeiten. 

So funktioniert das im groben.

- Alex


----------



## Wildcard (16. Mrz 2009)

Sollte dein Swing Client genauso funktionieren, dann ist übrigens auch der falsch, denn ein Background Thread darf auch in Swing nicht die Oberfläche verändern (nur leider wird dort keine Exception geworfen).


----------



## Koringar (17. Mrz 2009)

@tuxedo: Erstmal danke für deine Antwort. Sowas in der Art habe ich auch schon versucht, blos da ist wieder das Problem das es sich aufhängt, da er ja in regelmäßigen Abständen diese Liste immer wieder durchgehen muss bis das Programm beendet ist, also wieder so eine Art Endlosschleife.
Wie ich das mit den Listenern mache habe ich mir alles schon theoretisch überlegt und wenn sie so funktionieren wie ich denke, dann sollte es auch klappen. Blos mir fehlt da vollkommen die Praxis in Verbindung mit SWT, des wegen suche ich ja nach einem Tutorial.

@Wildcard: Das weis ich selber, da es aber unter Swing eben keine Exception wirft und alles so klappt, war das mit in erster Linie sowas von egal. Des wegen suche ich ja jetzt auch etwas, das mir damit hilft sowas zuerstellen.


----------



## tuxedo (17. Mrz 2009)

Koringar hat gesagt.:


> @tuxedo: Erstmal danke für deine Antwort. Sowas in der Art habe ich auch schon versucht, blos da ist wieder das Problem das es sich aufhängt, da er ja in regelmäßigen Abständen diese Liste immer wieder durchgehen muss bis das Programm beendet ist, also wieder so eine Art Endlosschleife.



Das runnable das du mit syncexec oder asyncexec ausführst darf keine Endlosschleife enthalten. Das ist der ganze Trick an der Sache. Du darfst da nur "kleine Jobs" die in der GUI erledigt werden müssen reinstecken. Mehr nicht. Die Endlosschleifenlogik musst du im Netzwerkthread oder anderswo handhaben.



> Wie ich das mit den Listenern mache habe ich mir alles schon theoretisch überlegt und wenn sie so funktionieren wie ich denke, dann sollte es auch klappen. Blos mir fehlt da vollkommen die Praxis in Verbindung mit SWT, des wegen suche ich ja nach einem Tutorial.



Glaub mir: Mit Listenern wird's nicht besser. Listener sind kein "Heilmittel" für das durchbrechen einer Thread-Barriere.

Selbst wenn du zwischen Netzwerkthread und GUI-Thread einen Listener hängst, der bei jedem eingehenden Chat-Paket benachrichtigt wird und dann die GUI benachrichtigt: Wenn du im GUI-Thread nun wieder viel zu erledigen hast blockiert dieser wieder.

Am besten wird's wohl sein du zeigst mal wie du syncexec, bzw. asyncexec benutzt hast und wie das Runnable aussah, das du da rein gesteckt hast.

- Alex


----------



## Koringar (18. Mrz 2009)

tuxedo hat gesagt.:


> Das runnable das du mit syncexec oder asyncexec ausführst darf keine Endlosschleife enthalten. Das ist der ganze Trick an der Sache. Du darfst da nur "kleine Jobs" die in der GUI erledigt werden müssen reinstecken. Mehr nicht. Die Endlosschleifenlogik musst du im Netzwerkthread oder anderswo handhaben.


Danke für den Hinweis, ist mir aber schon klar. Da das syncexec nie wieder zurück geht.



tuxedo hat gesagt.:


> Glaub mir: Mit Listenern wird's nicht besser. Listener sind kein "Heilmittel" für das durchbrechen einer Thread-Barriere.
> 
> Selbst wenn du zwischen Netzwerkthread und GUI-Thread einen Listener hängst, der bei jedem eingehenden Chat-Paket benachrichtigt wird und dann die GUI benachrichtigt: Wenn du im GUI-Thread nun wieder viel zu erledigen hast blockiert dieser wieder.
> 
> ...


KA ob es was bringen wird, würde es aber trotzdem gern mal Versuchen. Hatte diese Nacht auch wieder einen Einfall, wie es vielleicht klappen könnte, ich werde es einfach mal versuchen.
Den Code zeige ich dir dann mal, wenn ich es nicht schaffe.


----------



## Koringar (18. Mrz 2009)

JAHA:lol:!!!! Ich habe es geschaft, erstmal danke für eure Hilfe. Habs sogar ohne synchExec gemacht .

An der richtigen Stelle die Prüfung packen und schon funzt alles .

Würde mich aber trotzdem noch für die Listener interessieren, nur so.


----------



## tuxedo (19. Mrz 2009)

Wenn du jetzt noch verrätst wie du es gemacht hast, dann hat dieses Forum seinen Sinn und Zweck erfüllt.

- Alex


----------



## Koringar (20. Mrz 2009)

Im Grunde ist es ganz Simple,

1. habe ich eine Klasse geschrieben die eine List als Variable hat und die dazu gehörigen getter(naja eher ein adder, da er die Inhalte anfügt und nicht komplett neu macht) und setter. In dieser Klasse habe ich dann noch eine Mehtode die diese Varibale auswertet, dieser Methode werden die GUI-Elemente übergeben die dann geändert werden sollen.

2 . habe ich dem dem Thread, der die Nachricht empfängt, diese Klasse im Kontruktur mit übergeben. Nun gebe ich mit dieser Übergebenen Klasse über die adder Methode die Nachricht in die List und das war alles was dieser Thread macht.

3. habe ich an der Stelle wo SWT sowie so seine eigen Endlosschleife macht (für unwissende:
        while (!shell.isDisposed()){
            if (!display.readAndDispatch()){
                display.sleep();
            }
        }
) eine else if Bedingung angehängt, die überprüft ob die List leer ist. Wenn sie leer ist macht sie nichts und wenn sie mit etwas gefüllt ist springt sie dann in die unter 1. genannten Klasse und wertet die Nachricht aus. Da dieses Auswerten immer noch im Thread der GUI steckt braucht man kein syncExec und es kommt auch keine Exception.

Ich groben und ganzen wars das, habe das zwar noch etwas ausgebaut mit mehereren nebenher laufenten Threads damit die Annahme immer klappt, aber das ist ein anderes Thema


----------



## tuxedo (20. Mrz 2009)

Oha. Das klingt aber nach wie vor "unnötig". Grund:

readAndDispatch() arbeitet pro Call eine Liste mit Runnables ab. Wenn du jetzt den "Arbeitsteil", sprich das auswerten der Nachricht in solch ein Runnable mit asyncExec oder syncExec in diese Liste einreihst, wird das exakt so ausgeführt. 

Das was du jetzt gemacht hast ist das "ReadAndDispatch" Rad neu erfunden und damit aus einem "Einrad" ein "Zweirad" gemacht. 

Klar funktioniert das auch. "Sauberer" wäre es aber gewesen beim Einrad zu bleiben.

- Alex


----------



## Koringar (20. Mrz 2009)

naja, nur das meine verarbeitung kein zusätzlicher thread ist. macht auch wirklich kein sinn (von meiner sicht her), wenn man mit syncExec eh warten muss bis er fertig ist.

ich bin gern ein mensch der auf zweirändern fährt :lol:, so mache ich immer wieder. da ich bei manchen sachen noch nicht so die erfahrung habe obs dafür schon was gibt oder nicht und da mache ich das meistens selber (damit ich das auch besser verstehe, was da passiert).

aber danke für den hinweis.


----------



## tuxedo (20. Mrz 2009)

Man sieht dass du dich noch nicht durch die tiefen der SWT Logik gekäpmft hast.

Wenn du ein "Runnable" mittels "syncExec" oder "asyncExec" in den UI-Thread wirfst, hat das keinen neuen Thread zur Folge. Das Runnable landet in einer Liste. Und die read-and-dispatch-loop in deiner Hauptklasse, welche den Main-Thread darstellt, nimmt Durchlauf für Durchlauf ein Runnable aus der Liste raus und führt dessen "run()" Methode aus. Wäre ja sehr aufwenidg wenn die UI nicht Single-Threaded wäre ...

Du hast nun offensichtlich eine zweite Liste erstellt und machst das gleiche nochmal in grün. 

Klar, du kannst das bedenkenlos so lassen. Wird nicht schneller oder langsamer dadurch. Nur hast du eben das "Rad" neu erfunden  "Schöner" geht's mit dem bereits existierenden "Rad".

Zu "syncExec" und "asyncExec":
Da hab ich auch ne Zeitlang ein Problem gehabt zu verstehen was da letztendlich passiert. Aber wenn man's eiß ist es auf eingaml ganz einfach:

asyncExec steckt das Runnable einfach in die Liste mit anderen Runnables, welche von der read-and-dispatch-loop abgearbeitet wird. Dieses "hineinstecken" returned sofort. D.h. du wirfst das runnable einfach in den Pool und wartest nicht bis es ausgeführt wurde. 

Wenn du ein syncExec ausführst, blockiert dieser Aufruf solange, bis das Runnable von der read-and-dispatch-loop ausgeführt wurde. 

Das ist schon alles. Kannst dir ja mal die Sources von "Display" und "Synchronizer" anschauen. :idea:

Gruß
Alex


----------



## Wildcard (20. Mrz 2009)

tuxedo hat gesagt.:


> Wenn du ein syncExec ausführst, blockiert dieser Aufruf solange, bis das Runnable von der read-and-dispatch-loop ausgeführt wurde.


Warum? Das ist 1:1 die selbe Logik wie in Swing, nur das es in SWT IMO besser umgesetzt ist.


----------

