2.2.4. HelloWorldApplication - Der common Ui Code

Die Klasse HelloWorldApplication implementiert die Schnittstelle IApplication. Diese hat eine Startmethode, welche den Lifecycle als Parameter liefert. Wird auf diesem die Methode finish()aufgerufen, wird die Applikation beendet.

Will man jowidgets in nativen Ui Code (z.B. Swing oder SWT) integrieren, hat man in der Regel keine IApplication zum starten. Stattdessen werden das Root Fenster (z.B. Shell oder JFrame) und weitere Widgets (z.B. Composite, JPanel) nativ erzeugt. In Jowidgets Code in native Projekte integrieren wird erläutert, wie man in diesem Fall vorgehen kann.

  1  package org.jowidgets.helloworld.common;
  2  
  3  import org.jowidgets.api.toolkit.Toolkit;
  4  import org.jowidgets.api.widgets.IButton;
  5  import org.jowidgets.api.widgets.IFrame;
  6  import org.jowidgets.api.widgets.blueprint.IButtonBluePrint;
  7  import org.jowidgets.api.widgets.blueprint.IFrameBluePrint;
  8  import org.jowidgets.common.application.IApplication;
  9  import org.jowidgets.common.application.IApplicationLifecycle;
 10  import org.jowidgets.common.types.Dimension;
 11  import org.jowidgets.common.widgets.controller.IActionListener;
 12  import org.jowidgets.common.widgets.layout.MigLayoutDescriptor;
 13  import org.jowidgets.tools.widgets.blueprint.BPF;
 14  
 15  public final class HelloWorldApplication implements IApplication {
 16  
 17      @Override
 18      public void start(final IApplicationLifecycle lifecycle) {
 19  
 20          //Create a frame BluePrint with help of the BluePrintFactory (BPF)
 21          final IFrameBluePrint frameBp = BPF.frame();
 22          frameBp.setSize(new Dimension(400, 300)).setTitle("Hello World");
 23  
 24          //Create a frame with help of the Toolkit and BluePrint. 
 25          //This convenience method finishes the ApplicationLifecycle when 
 26          //the root frame will be closed.
 27          final IFrame frame = Toolkit.createRootFrame(frameBp, lifecycle);
 28  
 29          //Use a simple MigLayout with one column and one row 
 30          frame.setLayout(new MigLayoutDescriptor("[]", "[]"));
 31  
 32          //Create a button BluePrint with help of the BluePrintFactory (BPF)
 33          final IButtonBluePrint buttonBp = BPF.button().setText("Hello World");
 34  
 35          //Add the button defined by the BluePrint to the frame
 36          final IButton button = frame.add(buttonBp);
 37  
 38          //Add an ActionListener to the button
 39          button.addActionListener(new IActionListener() {
 40              @Override
 41              public void actionPerformed() {
 42                  System.out.println("Hello World");
 43              }
 44          });
 45  
 46          //set the root frame visible
 47          frame.setVisible(true);
 48      }
 49  }

Im Vergleich zu anderern UI Frameworks gibt es in jowidgets einen wesentlichen Unterschied bei der Widget Erzeugung. Widgets werden nicht direkt, also mit Hilfe des new Schlüßelwortes instantiiert, sondern von einer Factory erzeugt. Dies hat einige Vorteile, siehe dazu auch Die Generic Widget Factory.

Die Wigdet Factory benötigt für die Erzeugung eines Widgets ein sogenanntes BluePrint (Blaupause). Siehe dazu auch BluePrints. BluePrints erhält man von der BluePrint Factory. Die Klasse BPF liefert einen Zugriffspunkt auf alle BluePrints der BluePrint Factory. In Zeile 21 wird so das BluePrint für ein Frame und in Zeile 33 das BluePrint für einen Button erzeugt. BluePrints sind Setup und Builder zugleich. Sie werden dazu verwendet, das Widgets zu Konfigurieren und liefern dadurch der Implementierung das initiale Setup des Widgets. In Zeile 22 wird so die Größe und der Titel des Fensters gesetzt. In Zeile 33 wird so das Button Label definiert. BluePrints sind nach dem Prinzip des BuilderPattern entworfen, das heißt sie liefern die eigene Instanz als Rückgabewert, um verkettete Aufrufe zu ermöglichen.

In der Regel wird die Generic Widget Factory nicht explizit verwendet. Um das root Fenster zu erhalten, wird in Zeile 27 ein IFrame Widget mit Hilfe des frameBp und des Toolkit’s erzeugt. Bei der verwendeten Methode handelt es sich um eine convenience Methode die beim Schließen des Fensters den ApplicationLifecycle beendet. Das Frame ist gleichzeitig auch ein Container. Um ein Widget zu einem Container hinzuzufügen, fügt man das BluePrint hinzu und erhält dafür das Widget. In Zeile 36 wird so der Button erzeugt.

In Zeile 30 wird das Layout mit einer Spalte und einer Zeile für das Frame gesetzt. Zeile 39 fügt dem erzeugten Button einen Listener hinzu, welcher beim Klicken eine Konsolenausgabe macht. In Zeile 47 wird das Fenster schlußendlich angezeigt.

Fassen wir noch einmal zusammen:

Um Widgets zu erhalten, benötigt man vorab ein BluePrint. Dieses erhält man von der BluePrint Factory. Auf dem BluePrint kann man das Setup konfigurieren. Für ein BluePrint bekommt man dann ein Widget.

Auch wenn sich das vielleicht erst mal ungewohnt anhört, ist das auch schon alles, was im Vergleich zu anderen UI Frameworks generell anders ist.

Man wird zudem schnell feststellen, dass man dadurch sehr kompakten und zudem gut lesbaren UI Code erzeugen kann. Den im Vergleich zu langen Konstruktoraufrufen ist beim Builder Pattern immer klar, welchen Parameter man konfiguriert. Außerdem kann die Erzeugung von BluePrints meist auch implizit passieren. So könnte man den Code von Zeile 32 bis 36 auch so aufschreiben:

    final IButton button = frame.add(BPF.button().setText("Hello World"));

Zudem können BluePrints für die Erzeugung mehrerer Instanzen wiederverwendet werden, was sich oft als sehr hilfreich erweißt.

Anbei folgen noch ein paar Anmerkungen zum Code Style:

Unter dem Begriff CleanCode findet sich der Hinweis, immer sprechende Variablennamen zu verwenden, und insbesondere kryptische Variablennamen wie: is, os, hfu, jkl, … etc. zu vermeiden. Im Allgemeinen ist dem auch voll zuzustimmen.

Da jedoch BluePrints in jowidgets eine so fundamentale Rolle spielen, wird hier dennoch bewusst von dieser Regel abgewichen. Der Name der Abbreviation Accessor Klasse BPF wurde bewußt kurz gewählt, um eine bessere inline Verwendung (siehe oben) zu ermöglichen. (Wer das trotzdem nicht mag, kann anstatt BPF.button() auch Toolkit.getBluePrintFactory().button() schreiben.)

Um BluePrint Variablen besser von den eigentlichen Widget Variablen unterscheiden zu können, sollten diese per Konvention immer die Endung bp oder bluePrint haben. Wird das BluePrint nur für die Erzeugung eines einzelnen Widgets verwendet, bietet es sich an, für BluePrint und Widget den gleichen Präfix zu wählen, also zum Beispiel buttonBp und button.


Siehe auch PDF Version dieses Dokuments, Jowidgets API Spezifikation