Swing-Listeners ade!


Heute mal etwas Java. Während Scala mit dem in der Distribution enthaltenen ScalaSwing (als Wrapper um Swing) recht elegante GUI-Programmierung erlaubt, ist das originale Swing nicht so bequem, wie eine extrem wichtigen Bibliothek sein sollte. GUI-Programmierung ist ein dankbarer Anwengungsfall für Domänenspezifische Sprachen, aber Java ist eben nicht die richtige Sprache dafür. Und die guten Ansätze, die es gibt, werden nicht realisiert.

Eine Sache, die mir ganz besonders die Tränen in die Augen treibt, sind Listener. Funktionen erster Klasse (bzw. Closures) würden das Problem elegant lösen, aber da Java das leider nicht hat, habe ich den Vorschlaghammer ausgepackt: Annotations und jede Menge Reflection. Ja ich weiß, Reflection ist böse. Und ich fühle mich nicht wohl dabei. Und ich weiß, dass man sich damit mächtig in den Fuß schießen kann. Aber auf der anderen Seite wird der Drang, beim Tippen von „new ActionListener…“ so zu reagieren, immer stärker.

Der Vorschlaghammer hat wenigstens einen niedlichen Namen: Swirrel, die Kreuzung von Swing mit einem Eichhörnchen (Squirrel).

Wie es funktioniert? Nun, die Komponente muss als Member-Variable vorliegen, dann kann sie einfach mit dem Namen der aufzurufenden Methode annotiert werden:

@ActionPerformed("doSomething")
JButton button = new JButton("Do it!");

Wenn doSomething() z.B. in der gleichen Klasse definiert wäre, sähe der dazu äquivalente Listener so aus:

button.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent ae) {
       doSomething(); //oder doSomething(ae);
   }
});

Wenn die GUI fertig zusammengebaut ist, muss man eine statische Methode für jedes Top-Level-Fenster aufrufen, die dann überall nach solchen Annotations sucht und entsprechende Listener anhängt. Die spezifizierte Methode kann entweder kein Argument oder ein Argument der entsprechenden Event-Klasse (hier: ActionEvent) besitzen. Sie kann in der gleichen Klasse, in Superklassen oder den übergeordneten Containern (also all das, was über rekursive getParent()-Aufrufe zu erreichen ist) stehen. Das Aufrufen der statischen Methode ist lästig, also gibt es auch eine Unterklasse von JFrame, die das automatisch erledigt.

Natürlich muss man sich an die Regeln halten, soll einem das Ganze nicht zur Laufzeit um die Ohren fliegen. Insbesondere sieht man den Zielmethoden nicht an, dass sie reflektiv aufgerufen werden, also ist es eine gute Idee, ihren Zweck zu kommentieren, bevor man sie versehentlich umbenennt oder löscht. Es ist also etwas Disziplin gefordert – sagt nicht, ich hätte euch nicht gewarnt!

Swirrel ist noch in der Pre-Alpha-Phase und deckt noch längst nicht alle Listener ab. Bei meinen bisherigen Tests funktionierte die Bibliothek einwandfrei, aber ich freue mich natürlich über jedes Feedback. Hauptsache ihr setzt das Dingens noch nicht produktiv ein …

Advertisements

Ein Gedanke zu “Swing-Listeners ade!

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s