JavaFX2.0: Stage und Scene

Die Basis aller JavaFX 2.0 GUIs (egal ob im Web oder auf dem Desktop) ist Stage. Diese Klasse ist von Window abgeleitet, wie auch die Klasse PopupWindow.Das System stellt in der launch()-Methode eine Stage-Instanz zur Verfügung. Wie die Stage aussieht, kann man auf verschiedene Arten definieren: bei Fenstern können verschiedene Dekorationen ( enum StageStyle) definiert werden. Ausserdem kann ein Fenster als screen-füllend oder skalierbar definiert werden (resizable(true/false)). Bei jedem Stage kann festgelegt werden, ob es sich um ein modales Fenster handelt(initModality()) und zu welchem anderen Fenster es gehört. Dieses Fenster würde dann durch ein modales Fenster blockiert. Es gibt drei verschiedene Arten von Modality: NONE, APPLICATION_MODAL und WINDOW_MODAL. Während sich APPLICATION_MODAL auf die gesamte Applikation bezieht, blockiert WINDOW_MODAL lediglich die Hierarchie der Fenster, wie durch initOwner(...) definiert. Auf dieser Stage (engl. Bühne) wird in einer Scene (engl. Szene) der Screen-Inhalt aufgebaut.

Im Gegensatz zu Swing basiert JavaFX2.0 auf einem sogenannten Scene Graph, ähnlich HTML. Dabei handelt es sich um eine Baumstruktur, die den Inhalt eines Fensters beschreibt und in einer Scene abgelegt wird. Diese Scene wird so einem Fenster zugewiesen: myStage.setScene(myScene);

Für die Konstruktion einer Scene ist mindestens ein Parent notwendig. Ein Parent ist ein spezieller Typ von Node und Node ist die Basisklasse sämtliche Klassen die einen Block im GUI repräsentieren (egal, ob unsichtbare oder sichtbare Komponenten; dazu später mehr).

Auf dem Level einer Scene lassen sich unter Anderem Tastaturkürzel (Accelerators) definieren. Eine ähnliche Variante ist der Einsatz von Mnemonics. Der Unterschied zum Accelerator liegt darin, dass hier ein Tastatürkürzel mit einem GUI-Komponente (Node) verknüpft wird. Sobald ein Benutzer eine Tasten-Kombination drückt, wird ein ActionEvent an die definierte GUI-Komponente ausgelöst. Desweiteren lässt sich der Typ des Cursors setzen. Zur Auswahl etwa 20 Varianten, die in der enum Cursorgespeichert sind.

Eine Scene kann eine breite Palette von Events behandeln (diverse Eingabe-Variationen mit Maus und Tastatur, und Drag'n'Drop).

Auf diesem Level lassen sich CSS als Stylesheets definieren. Da JavaFX sehr umfassenden CSS-Support anbietet, empfiehlt es sich möglichst viel des Erscheinungsbilds in CSS auszulagern. Zu beachten ist, dass JavaFX-basiertes CSS nicht 100% mit Web-basiertem CSS übereinstimmt. Die Verwendung ist sehr ähnlich, aber es gibt durchaus Unterschiede. Von der Verwendung von JavaScript rate ich eher ab. Schliesslich können wir GUI-nah in Java programmieren; da macht ein Einsatz von JavaScript eher wenig Sinn.

Im nächsten Blog gehe ich auf die Subklassen von Node ein, die für das Layout von GUIs verwendet werden.

automatisches Scaling von JavaFX2.0-Controls

Getestet habe ich mit folgendem Code-Block unter JavaFX2.1-Beta unter Mac OS X 10.7 und Java 6:

 HBox p = HBoxBuilder.create().children(btn, btn1).build();
 HBox.setHgrow(btn, Priority.NEVER);
 HBox.setHgrow(btn1, Priority.ALWAYS);

Folgende Liste enthält die JavaFX2-Controls, die ihre Grösse in einer HBox (oder anderem Layout, welches die enthaltenen Elemente skaliert) automatisch anpasst:

- javafx.scene.control.ListView - javafx.scene.control.Slider - javafx.scene.control.TableView - javafx.scene.control.TextField - javafx.scene.control.TreeView

Diese JavaFX2-Controls benötigen das explizite Setzen der maximalen Breite bzw. Höhe:

- javafx.scene.control.Button - javafx.scene.control.ProgressBar - javafx.scene.control.ToggleButton

Bei folgenden Gui-Controls macht Scanning keinen Sinn:

- javafx.scene.control.CheckBox - javafx.scene.control.Label - javafx.scene.text.Text

javafx.scene.control.TextArea ignoriert Hgrow komplett

Tipps und Tricks zu JavaFX2.0

Ich lerne gerade JavaFX2.0 kennen und sammle hier meine Erkenntnisse zu einzelnen Themen. Wieso JavaFX2.0? Hauptgrund sind zum Einen die Erwartungen der Benutzer, die mit einem simplen Formular und ein paar Bildchen nicht mehr zu begeistern sind und zum Anderen die unüberschaubare Anzahl von Web-Frameworks, die am Ende des Tages doch an Browser-Inkompatibilitäten scheitern.

Bei JavaFX2.0 geht es darum, die Produktivität zu erhöhen, in dem der Benutzer seine gewohnten Handgriffe schneller und zuverlässiger ausführen kann.

Dabei geht's um verschiedene Aspekte: Funktionalität, Zuverlässigkeit und Optik.

Los geht's mit Funktionalität:

JavaFX2.0 ist Java. Alles was in der Vergangenheit clientseitig funktioniert hat, ist immer noch korrekt. Dazu kommen starke Controls, wie WebView, TableView, TreeView und Toolbar und GUI-Elemente für die Organisation des GUIs, wie Accordion. Dazu gleich mehr ...

Zentral sind Properties und Bindings. Properties erinnern an getter-/setter-Methoden aus JavaBeans-Zeiten (also: gestern). Zusätzlich zur Basisfunktionalität der Kapselung bieten Properties Observable-Funktionalität und Support für Binding. Grundsätzlich können Properties über Binding verknüpft werden. Das bedeutet, dass bei der Änderung eines Properties andere Properties automatisch neu gesetzt (z.B. berechnet) werden. Mehr Infos hier. Beide Themen sind zentral für JavaFX.

Tipp zu Binding: für Layout nie Binding verwenden. Die Performance leidet und der Code wird unlesbar. Verwende die entsprechenden Panes für die optische Anordnung von GUI-Elementen. Optimal für Bindings sind die Datenstrukturen hinter Tabellen, Trees oder eigenen JavaFX2.0 GUI-Elementen. Der Callback in die GUI Aktualisierung entfällt, wenn Datenstrukturen direkt mit den zugehörigen Elementen verknüpft sind.

JavaFX2.0 kommt mit neuen Collections (List und Map-style), die einen über inhaltliche Änderungen informieren. Beide lassen sich von FXCollections aus herkömmlichen Collections erzeugen.

WebView

Hierbei handelt es sich um eine komplette webkit-basierte HTML-Engine inkl. JavaScript, die überall ins GUI integriert werden kann. Der Inhalt kann über eine URL oder direkt als HTML übergeben werden.

URL:

 WebView wv = new WebView();
 WebEngine we = wc.getEngine();
 we.load("http://...");

direkt als HTML:

 WebView wv = new WebView();
 WebEngine we = wc.getEngine();
 we.loadContent("...");

TableView

Im Unterschied zu Swing entfällt die Implementierung eines TableModels und die ganze optische Gestaltung ist in CSS ausgelagert. Somit beschränkt sich die Implementierung der TableView auf die Funktionalität.

Dank Generics können Tabellen einfacher gebaut werden als früher unter Swing. Dazu braucht man zuerst ein Model-Klasse, die eine Zeile der Tabelle repräsentiert. Dazu reicht im Prinzip ein POJO; in den Beispielen sieht man häufig Beans mit Properties. Dies hilft natürlich sehr, wenn man automagisch aktualisierte Werte braucht.

Wenn man das Model hat, definiert man Tabellenspalten und fügt sie der TableView hinzu. Im Unterschied zu früher ist Sortierung (auch nach mehreren Spalten [aktivierbar mit SHIFT] ) standardmässig integriert. Die Optik kann mit CSS angepasst werden.

TreeView

Ähnlich wie bei der TableView entfällt auch hier die explizite Model-Implementierung. Man baut einen Baum mit TreeItems mit der Methode node.getChildren().add(myNode). Als Label für ein TreeItem wird toString() auf dem enthaltenen Value verwendet.

ToolBar

Eine ToolBar bietet kaum Überraschungen. Es lassen sich Effekte auf eine ToolBar anwenden; sinnvoll ist dies nicht. Schön wäre es eine ToolBar detachable zu definieren. Dies scheint aber (noch) nicht zu gehen.

 

Nun zur Zuverlässigkeit:

Es lohnt sich Auswahllisten und Daten, die selten ändern oder gar historische Daten sind, lokal zu speichern (mindestens in memory, evtl. auch echt persistent). Sämtliche aus der Client-Server-Entwicklung bekannten Tricks sind hier nicht verkehrt. Einzig das Bauen von GUIs "auf Vorrat" lohnt sich weniger. Gegenüber Panel-basierten GUIs mit GridBagLayout ist die Performance-Steigerung bei JavaFX2.0 enorm.

Zum Schluss die Optik:

Keep it simple! Perfekte Farbkombinationen und Schatten werden nie entsprechend honoriert. Im Gegenteil! Die hier verwendete Zeit bekommt keine Budget-Position. Beim Bauen eines GUIs mit einfachen Layouts anfangen und Benutzer-Feedback abwarten. Mit JavaFX2.0 sind GUIs so schnell neu oder umgebaut und diese Arbeiten sind so non-invasiv, dass ein gewaltiges Investment in Optisches fehlgeleitet ist.

Layout

HBox und VBox sollten nicht sehr tief geschachtelt werden. Das kostet Performance. Wahrscheinlich hilft eine GridPane diese Verschachtelungen zu vermeiden. Verwende kein Binding damit ein GridPane sich der Grösse des Fensters anpasst.

Gradients

Farbübergänge lassen sich in JavaFX2 sehr einfach erzeugen. Es gibt zwei Klassen dafür: LinearGradient und RadialGradient mit dem jeweiligen Buildern dazu. Am Besten zu Enterprise GUIs passen üblicherweise dezente, lineare Farbübergänge im Graubereich (oben hell / unten etwas dunkler) auf Fensterebene. Mit einem dunkleren Farbübergang (oben dunkelgrau / unten schwarz) lässt sich ein Adobe Flash Effekt erzielen. Dies kann hilfreich sein, wenn man User dieser Plattform "abholen" will.

CSS

Einem GUI (egal ob browser-basiert oder window-basiert) liegt immer ein DOM-Baum zugrunde, der die Struktur dieses GUIs definiert. Will man nun einen Knotenpunkt (Node) innerhalb eines solchen DOMs finden, kann man entweder drüber iterieren (beginnend mit myScene.getRoot()) oder man sucht den Node direkt über seinen Namen:

 Node n = parentNode.lookup("...");

Dies setzt natürlich voraus, dass vorgängig mit myNode.setId("...") eine eindeutige Id vergeben wurde.

Diese Ids können dann in CSS-Files verwendet werden.

Hier ein paar Tricks, wie man einer Applikation einen einheitlichen, neuen Farbstil geben kann:

-fx-base:/* Basisfarbe für alle Komponenten */

-fx-text-base-color:/* Textfarbe */

-fx-accent: /* Standard Knöpfe ... */

-fx-focus-color: /*Farbe für die Anzeige des aktuellen Fokus */

-fx-mark: /* Farbe für Markierungen (CheckBoxen, Menüs, ...) */

Animationen

JavaFX2.0 ermöglicht es fast Alles irgendwie zu animieren. Aber man muss hier natürlich den Anwendungsfall im Auge behalten. Der Einsatz von Animationen in Spielen drängt sich ja meistens geradezu auf, aber in Business Applikationen ist davon abzuraten. Es mag die ersten paar Mal toll aussehen, aber schon nach kurzer Zeit nervt's den Benutzer. Es mag Fälle geben, in dem man den Benutzer mit einer Animation bspw. auf einen aktuell laufenden Prozess hinweisen möchte, aber im Zweifelsfall: Finger weg von Animationen!

Effekte

JavaFX bietet eine Vielzahl von Effekten. Hier gilt aber dasselbe, wie bei Animationen: nur mit besonders gutem Grund brauchen. Vielleicht eine Ausnahme sind Fade-Out und Fade-In. Sie können gut funktionieren, wenn sie dem Benutzer einen klaren Hinweis geben sollen (z.B."Ich brauche hier Input"). Aber dann sollten sie schnell sein (ca 250 ms) und konsistent verwendet werden.

Bei allen Aspekten rund um die Optik: eine kleine Bibliothek von vordefinierten Styles anlegen und diese dann entsprechend und konsequent verwenden. Das gibt ein einheitliches GUI. Unbedingt CSS einsetzen, damit die Optik später von einem CSS-Profi anpassbar ist. Niemand will im Java-Code die Optik pflegen.

JBoss 7 - Was ist neu?

JBoss ist ein sehr weit verbreiteter Application Server, der eigentlich nicht explizit vorgestellt werden muss. Fast jeder hatte irgendwann mal was damit zu tun. (Streng genommen ist JBoss kein Application Server, sondern Name einer Produktfamilie. Genauso wie WebSphere eigentlich kein spezifisches Produkt bezeichnet. Ich werde mir die Struktur der Produktfamilie in einem anderen Blog vornehmen)

Grundsätzlich gibt es die frei verfügbare Version von JBoss und die kostenpflichtige Fassung rund um JBoss EAP (Enterprise Application Plattform). Die freie Version ist EAP quasi immer einen technologischen Schritt voraus. Ein Blick auf JBoss AS 7 zeigt also was in EAP 6 kommen könnte. Da JBoss beim Wechsel auf Version 7 keinen evolutionären sondern einen revolutionären Schritt gemacht hat, möchte ich die wichtigsten Unterschiede hier zusammenfassen.

Es fängt damit an, dass AS7 praktisch komplett neu entwickelt wurde. Die etablierten Bausteine (z.B. Microcontainer) wurden ersetzt und durch eine grundsätzlich andere Architektur ersetzt. Zentraler Unterschied der neuen Architektur ist der modulare Aufbau, dank dem Komponenten erst bei Bedarf gestartet werden. In Profilen kann definiert werden, welche Komponenten anfänglich gestartet werden.

Das Modulsystem nennt sich JBoss Modules und ist ein eigenständiges Projekt, welches auch für andere Projekte eingesetzt werden kann (es geht in die Richtung der für Java 7 versprochenen Modullösung (JSR 294), welche nun bis Ende 2012 als Teil von Java 8 verschoben wurde). Unter Modul wird eine Komponente verstanden, die mit eigenen Ressourcen und Klassen daher kommt und Abhängigkeiten zu anderen Modulen hat. Diese Abhängigkeiten definieren, welche Funktionalitäten von Modul B Modul A sehen kann. Dies entspricht quasi einem 5. Visibility Level in Java, also einer Steigerung von 'public'. Dieser Ansatz löst massenweise Probleme: die Startup-Zeit und der memory footprint wurden massiv verringert. Viel wichtiger ist, dass Module jeweils mit eigenem ClassLoader kommen und die mühseligen ClassPath-Problematiken der Vergangenheit angehören.

JBoss 7 unterstützt Hibernate, Weld, Mojarra und viele weitere opensource Standards. JBoss 7 bietet JavaEE6 Support (Web-Profile; Full Profile folgt in 7.1 später dieses Jahr).

Eine weitere, gut sichtbare Änderung ist das neue GWT-basierte Admin-GUI. Es lässt sich darüber streiten, ob ein solches GUI notwendig war; aber besser aussehen tut's auf jeden Fall ;-)

Neu unterstützt JBoss AS 7 zwei Betriebsmodi: standalone und domain. Stand-alone entspricht ungefähr der bisherigen Betriebsweise. Dabei laufen alle Komponenten (Host Controller und einer oder mehrere managed Application Server auf derselben Maschine). Ein Deployment besteht aus dem Kopieren des WAR-Files nach /standalone/deployments. Dieses Verzeichnis wird vom Deployment Scanner überwacht. Via Filename-Anpassungen wird über den (Miss-)Erfolg von Deployments informiert (neue File-Endung '.deployed' oder '.failed'). Domain unterstützt die Verwaltung mehrerer gemanagte Server (auch auf unterschiedlichen Maschinen). Neben HC und AS kommt bei Domain auch noch ein Domain Controller zum Einsatz, der die einzelnen HCs überwacht. Die einzelnen Application Server werden üblicherweise in Servergruppen zusammengefasst, die betriebliche Funktionen haben (z.B. Test, Integration, Produktion). Diese Servergruppen können mehrere physikalische Server belegen. Applikationen werden in eine Domain geladen und können dann in den verschiedenen Umgebungen deployed werden (Achtung: Konfigurationsdetails wie DB, Log-Settings, ...). Ein Deployment via File copy ist nicht mehr möglich.

Eine weitere spannende Möglichkeit ist die Integration von JBoss in Unit und Integration Tests. Während in vielen Fällen Unit-Tests gar keinen laufenden Application Server mehr benötigen (Stichwort: POJO), gibt es doch noch einige Fälle in denen ein solcher notwendig wäre. Häufig scheitert es daran, dass "professionelle" Application Server nicht sinnvoll in Tests integriert werden können, da sie zu lange zum Starten brauchen, man nicht die entsprechenden Einstellungen mitgeben kann oder eine Integration in einen Testlauf einfach nicht machbar ist. Natürlich gibt es die Möglichkeiten Jetty für gewisse Tests einzubinden, aber der verhält sich wahrscheinlich leicht anders als das System, welches produktiv zum Einsatz kommt. Kurz: man will auf dem Server testen, welcher am Ende des Tages produktiv zum Einsatz kommen wird.

Last but not least, gibt es in JBoss 7 eine Kommandozeile (bin/jboss-admin.sh) für die Administration ohne WebGUI. Mittels Batch-Blöcken lassen sich mehrere Änderungen in einer Transaktion ausführen, um den Server nicht 'unterwegs' in inkonsistente Zustände zu bringen.

Entwickeln für NetBeans Plattform

Ich arbeite schon länger mit NetBeans, aber mit der Plattform für eigene Applikationen habe ich noch nie was gemacht. Es folgen meine Notizen für die ersten Schritte. NetBeans enthält in den Standard-Installation schon alles für die Entwicklung eigener client-seitiger Applikationen. Spannend: es ist auch möglich Maven-basierte NetBeans-Plugins zu schreiben. Aber ich probier's erst einmal klassisch:

Schritt 1

Neues Projekt erstellen: NetBeans Modules -> NetBeans Platform Application Nach einer Weile steht da ein Projekt, bestehend aus einem leeren Modulverzeichnis und einem Folder "Important Files". In letzterem ist ein ANT-Build File und drei Properties Files.

Schritt 2

Wenn ich das nun laufen lasse, wird ein zweites NetBeans gestartet. Die generierten Menüs sind recht umfassend für eine leere Applikation; die Taskleiste ist hingegen ziemlich leer.

Schritt 3

Irgendwie muss ich nun Funktionalität hinzufügen. Ein Rechts-Klick auf "Modules" scheint mir die Möglichkeit zu geben ein neues Modul zu bauen.

Schritt 4

Ich baue ein Login-Modul via "Add new ...". Zum neuen Modul kann ich ganz einfach ein Fenster hinzufügen und mit Mantisse das GUI bauen. Super einfach! Bevor ich nun weitermache, schaue ich mir die Videos auf http://platform.netbeans.org/tutorials/nbm-10-top-apis.html an.

Share

Kommentare in Java-Klassen

Kommentare haben fast so einen schlechten Ruf wie Testklassen, dabei sind sie fast genauso wichtig wie diese. Schliesslich helfen beide dabei, wartbare Applikationen zu schreiben. Je nachdem ist man selbst der direkt Betroffene, wenn man in ein paar Monaten an dieser Applikation eine Anpassung machen muss und nicht mehr weiss, um welchen Spezialfall es sich hier genau handelt. Deshalb lohnt es sich hier ein bisschen Zeit zu investieren. Ich möchte kurz meine Erfahrungen zum Thema 'Sourcecode kommentieren' beschreiben.

Nie den Sourcecode 1:1 kommentieren

Es bringt nichts im Kommentar zu schreiben, was bereits programmiert wurde. Wieso sollte jemand folgendes lesen wollen?

//füge Adresse in Adressliste ein
adresslist.add(adress);

Das hilft niemandem weiter. Kommentare müssen einen Mehrwert liefern. Also macht es zum Beispiel Sinn vor einem komplexen Algorithmus dessen Namen in den Kommentar zu schreiben.

Bei Business-Funktionen ist es sinnvoll Referenzen in die Spezifikation oder ins Issue Management System in die Kommentare zu schreiben. Wenn aus der Spez oder dem Issue dieses Implementierungsdetail nicht hervorgeht und es sich um einen genügend komplexen Codeblock handelt, sollte hier direkt ein Kommentar stehen, was man hier programmiert.

Sprache der Kommentare

Wenn das Team deutsch spricht, alle Dokumente deutsch sind und der Sourcecode intern bleibt, dann ist es irr englisch zu kommentieren.

JavaDoc in Schnittstellen

Schnittstellen beinhalten Methoden, die von anderen Teilen der Applikation aufgerufen werden. Hier ist eine Dokumentation besonders wichtig, da IDE's die Beschreibungen bei der Arbeit mit diesen Schnittstellen darstellen.

Keine Namen

Es bringt nichts in Kommentaren den eigenen Namen hineinzuschreiben. Diese Information kommt aus dem Sourcecode Verwaltungssystem (SVN, CVS, ...).

Review

Wie "normaler" Code sollten auch Kommentare reviewt werden. Was nützt ein Kommentar den niemand sonst versteht?

Share