Im fünften Teil unseres Java-Tutorials führen wir das Thema Oberflächengestaltung fort. Haben wir uns in Teil 4 mit den Grundlagen von Swing beschäftigt, geht es nun um JavaFX. Sie lernen, wie man JavaFX-UIs im Code und mit dem Design-Werkzeug Scene Builder baut. Zum besseren Nachvollziehen übertragen wir unser Code-Beispiel \"Word Cloud\" von Swing nach JavaFX.
Java-Tutorial Teil 5: Inhalt
Desktop-Anwendungen, die mit Swing gebaut werden, sehen gelegentlich etwas altbacken aus. Deutlich mehr visuellen Glanz verspricht JavaFX. Diese Bibliothek ist seit einigen Versionen Bestandteil des JDK und muss nicht erst extra installiert werden.
Durch einige technische Unzulänglichkeiten ist sie jedoch nicht so richtig aus dem Knick gekommen. Eine eigene Sprache JavaFX Script war wohl der falsche Weg. Oracle hat sich nun seit längeren zu JavaFX bekannt. Um damit ein modernes UI zu bauen, braucht es nunmehr nur noch Java. Wir haben unsere Beispielanwendung nach JavaFX konvertiert. Sehen Sie selbst, wie das funktioniert!
Java-Tutorial für Einsteiger: Professionell von Beginn an!
Dieses Java-Tutorial führt Sie Schritt für Schritt in die Programmierung mit Java ein. Anhand einer durchgängigen GUI-Beispielanwendung werden die wichtigsten Programmierkonzepte, Sprachkonstrukte und Werkzeuge in einem professionellen Setting vorgestellt.
Moderne Applikationen sollen heute nicht nur funktional fehlerfrei, sondern auch ansprechend im Design sein. Diese Aussage gilt nicht nur für privat genutzte Apps, sondern auch für klassische Business-Anwendungen, die oft in Java erstellt werden. Das User Interface (UI) soll dabei zu einem positiven Benutzererlebnis beitragen. Trotz Plattformunabhängigkeit und seit langem auch guter Performance besteht bei vielen Anwendern genau aus diesem Grund eine grundsätzliche Skepsis gegenüber in Java programmierter Software. Eine typische Aussage ist: „Die Oberfläche wirkt angestaubt“. Irgendwie kann das gesamte Erscheinungsbild nicht mit nativen Anwendungen mithalten.
Moderne Benutzeroberflächen arbeiten mit vielfältigen Features, beispielsweise Flat-Design, Transparenz-Effekten, modern gestalteten Steuerelementen und vielem mehr. Prägend sind die designtechnischen Entwicklungen der mobilen Plattformen. Apps für iOS, Android und Windows 10 haben viel dafür getan, dass Software nicht nur funktioniert, sondern dass es auch Freude macht, die Programme zu bedienen.
Lesen Sie auch: 20 JavaFX-Anwendungen aus der Praxis: So schön kann ein Java UI sein!
Für Windows gibt es mit Windows Presentation Foundation schon seit langem eine entsprechende Technologie, die es erlaubt, auch für den Desktop moderne und ansprechende Oberflächen zu gestalten. Java hatte hier lange Zeit einen deutlichen Nachteil. Nachhelfen konnte man mit Komponenten von Drittherstellern. Insgesamt musste man jedoch einigen Aufwand betreiben. Der Grund ist recht simpel: Die etablierte Swing-Technologie ist über die Zeit einfach in die Jahre gekommen.
JavaFX war bereits 2006 angetreten, um diesen Missstand zu beheben. Technologische Hürden und organisatorische Stolpersteine verhinderten jedoch lange Zeit einen Durchbruch. Heute ist JavaFX Bestandteil des JDK, und man kann es zur Erstellung moderner Oberflächen produktiv anwenden. Um Sie mit JavaFX vertraut zu machen, haben wir in diesem Online-Artikel folgende Informationen für Sie zusammengestellt:
Lassen Sie uns starten!
Wie integriert sich JavaFX in Java? Die Antwort auf die Frage finden Sie, wenn Sie sich Abbildung 1 intensiv betrachten. Gezeigt wird die Architektur von JavaFX.
Auf unterster Ebene befindet sich erwartungsgemäß die Java Virtual Machine (JVM). Was ist Prism? Es handelt sich um eine relativ neue Rendering Engine für Grafiken. Diese greift – sofern verfügbar – auf die Grafikhardware des Rechners zurück. Unter den Betriebssystemen OS X und Linux wird mit Hilfe von OpenGL gerendert. Unter Windows wird Direct 3D verwendet. Gibt es keine Unterstützung durch die Hardware beim Rendering, so wird auf Java 2D zurückgegriffen. Das Glass Windowing Toolkit stellt Low-Level-Betriebssystemroutinen zur Verfügung. Dazu gehören die Fenster- und Ereignisverwaltung. Die Media Engine bietet Unterstützung für Audio und Video. Die Web Engine ermöglicht das Einbetten von Web-Inhalten. Alle genannten Elemente von JavaFX werden über das Quantum Toolkit miteinander verknüpft. Dem Programmierer wird ein JavaFX API zur Verfügung gestellt. Darüber erfolgt die gesamte Kommunikation. Ein tieferes Wissen über die angesprochenen Elemente von JavaFX ist daher nicht unbedingt notwendig.
Grafische Applikationen laufen meist in Form eines Lebenszyklus ab. Dieses ist bei einer JavaFX-Anwendung nicht anders. Der Lebenszyklus einer JavaFX-Anwendung besteht aus den Methoden:
launch => init => start => stop
JavaFX-Anwendungen leiten von der Klasse Application ab. Die genannten Methoden werden damit vererbt und müssen durch Überschreiben mit eigenem Leben gefüllt werden. Der ursprüngliche Einstiegspunkt für eine Java-Anwendung ist bekanntermaßen die main-Methode. Von dieser wird direkt an die launch-Methode weitergeleitet und damit beginnt der Lebenszyklus. Innerhalb der init-Methode können Aufrufparameter der Applikation ausgelesen werden. Diese Methode kann auch leer bleiben. Die start-Methode ist der Kernpunkt einer JavaFX-Anwendung. Diese muss überschrieben werden. JavaFX übergibt der Methode ein Objekt vom Typ Stage (Bühne). Darunter versteht man eine Art Hauptcontainer. Wie lange läuft eine JavaFX-Anwendung? So lange, bis das letzte Fenster der Applikation geschlossen wurde oder die Methode Platform.exit aufgerufen wird.
Der Methode start wird ein Parameter der Klasse Stage übergeben. Innerhalb eines Stages-Objektes können eine oder mehrere Scene-Objekte präsentiert werden. Die Analogie zu einem Theater ist offensichtlich. Stage ist die Bühne, und auf dieser können eine oder mehrere Szenen spielen. Über Eigenschaften kann das Stage-Objekt konfiguriert werden. Dazu gehören zum Beispiel die Größe (setWidth, setHeight) oder der Titel (setTitle).
Ein Objekt der Klasse Scene ist wiederum hierarchisch aufgebaut. Es handelt sich um einen Baum (Tree), der aus einzelnen Knoten besteht (Nodes). Knoten wiederum können so genannte Parent-Nodes enthalten. Diese sind visuell nicht sichtbar (zum Beispiel BorderPane, HBox, VBox) und nehmen weitere Elemente (Kinder) auf. Kind-Elemente sind die typisch sichtbaren Elemente eines UI, wie Buttons, Textfelder usw. Auf diese Weise können mit JavaFX ganze Szenen erstellt werden. Eine Szene wird innerhalb der Stage-Klasse zur Anzeige gebracht. Auch JavaFX verwendet eine relative Anordnung der Elemente. Wenn Größenänderungen am Fenster erfolgen, erfolgen die Anpassungen in der Szene automatisch.
Ein Beispiel sagt bekanntlich mehr als 1.000 Worte! Das ist bei JavaFX nicht anders. Traditionell folgt daher ein einfaches „Hello World“. Legen Sie dazu in NetBeans ein neues Projekt an und wählen Sie im Assistenten im Ordner JavaFX Application (Abbildung 2).
Danach passen wir den Quellcode gemäß dem folgenden Listing an:
public class HelloWorld extends Application {
private Label;
@Override public void init() {
label = new Label("Hello World");
}
@Override public void start(Stage stage) {
StackPane root = new StackPane();
root.getChildren().add(label);
Scene = new Scene(root, 200, 200);
stage.setTitle("Hello World Example");
stage.setScene(scene);
stage.show(); }
@Override public void stop() {
}
public static void main(String[] parameters) {
launch(parameters);
}
}
Sehen wir uns diese paar Zeilen Quellcode in Ruhe an:
Damit haben Sie das Prinzip einer JavaFX-Applikation verstanden. Anwendungen jenseits von Hello World haben natürlich mehrere Fenster und eine Vielzahl von Steuerelementen. Diese werden alle innerhalb der start-Methode generiert. Dabei kann man gestuft vorgehen und das UI modular aufbauen. Das Prinzip bleibt jedoch gleich.
Muss man Java-Applikationen mit der Hand bauen? Nein, das wäre ein Rückschritt. Wichtig ist es jedoch zu wissen, dass die grundsätzliche Möglichkeit dazu besteht, d.h. das gesamte UI kann im Java-Code erzeugt werden. Zur Verfügung steht auch ein recht komfortabler UI-Designer, namens Scene Builder. Dieser kann direkt in die Entwicklungsumgebung, zum Beispiel NetBeans, eingebunden werden. Um mit diesem Tool zu arbeiten, startet man am besten wiederum ein neues Projekt, und dieses Mal wählen Sie JavaFX FXML Application (Abbildung 3).
Der Name des Projektes (FXML) sagt es schon: Grundlage für die Definition des UI ist ein XML-Dokument. Das UI wird hier deklarativ erstellt. Sieht man sich die Projektstruktur an (Abbildung 4), fällt einem sofort die Datei FMXLDocument.FXML auf.
Diese können wir wie gewohnt in NetBeans öffnen und bekommen den folgenden XML-Quelltext:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111" fx:controller="javafxapplication3.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="126" layoutY="90" onAction="#handleButtonAction" text="Click Me!" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<CheckBox layoutX="191.0" layoutY="28.0" mnemonicParsing="false" text="CheckBox" />
</children>
</AnchorPane>
Der Quelltext ist hierarchisch strukturiert, und man erkennt, dass zwei Steuerelemente (ein Button und ein Label) definiert werden. Statt die Datei in NetBeans zu öffnen, können Sie diese auch im Scene Builder bearbeiten (Abbildung 5).
Das Tool Scene Builder (Abbildung 6) wird gestartet. Hier ist eine umfangreiche Bearbeitung des UI möglich.
Speichert man die Änderungen und schließt das Tool, werden die Änderungen nach NetBeans übertragen und die o.g. XML-Datei wird aktualisiert. Zur Vollständigkeit zeigen wir die Methode start, in welcher das FMXLDocument.FXML geladen wird.
public class JavaFXApplication3 extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Sie erinnern sich noch an unser Beispiel aus den vorangegangen Teilen des Tutoriums? Richtig, wir hatten damit begonnen, den Rahmen eines Word-Cloud-Generators zu erstellen. Unser bisheriges Projekt basierte auf Swing. Nun übertragen wir das UI nach JavaFX. Dazu starten wir ein neues JavaFX-Projekt und definieren die Oberfläche neu – diesmal ohne UI-Builder. Wir definieren den Aufbau des UI direkt in Java. Dieser fällt nun etwas umfangreicher als beim Einführungsbeispiel aus.
public class JavaFX_Tutorial extends Application {
Stage window;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Word Cloud");
//Vbox - Hauptlayout
VBox haupt = new VBox();
haupt.setSpacing(10);
haupt.setPadding(new Insets(8,8,8,8));
//HBox top, obere Leiste mit Buttons
HBox top = new HBox();
top.setSpacing(10);
//Buttons in top
Button buttonSave = new Button();
buttonSave.setPrefSize(100, 20);
Image speichern = new Image(getClass().getResourceAsStream("save32.png"));
buttonSave.setGraphic(new ImageView(speichern));
Button buttonShow = new Button("Show");
buttonShow.setPrefSize(100, 20);
//buttom enhält alle Elemente unter top
HBox bottom = new HBox();
bottom.setPadding(new Insets(0,0,0,0));
bottom.setSpacing(10);
//Pane kann als Zeichenfläche genutzt werden
Pane canvas = new Pane();
canvas.setStyle("-fx-background-color: white;");
canvas.setPrefSize(700,550);
//TabPane mit Tabs einfügen
TabPane tabPane = new TabPane();
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
Tab tab1 = new Tab();
tab1.setText("Content");
Tab tab2 = new Tab();
tab2.setText("Style");
tabPane.getTabs().addAll(tab1, tab2);
tabPane.setPrefHeight(600);
tabPane.setPrefWidth(220);
Pane contentTab1 = new Pane();
contentTab1.setStyle("-fx-background-color: #eeeeee;");
tab1.setContent(contentTab1);
Pane contentTab2 = new Pane();
contentTab2.setStyle("-fx-background-color: #eeeeee;");
tab2.setContent(contentTab2);
//Buttons und Textfeld unter Tabpane
Button insertButton = new Button();
insertButton.setText("Add word");
insertButton.setPrefWidth(220);
TextField wordText = new TextField();
//Neue Vbox mit Tabs, Textfeld und Button
//Insert VBOX
VBox bottomRight = new VBox();
bottomRight.setPadding(new Insets(0));
bottomRight.setSpacing(8);
bottomRight.setPrefHeight(800);
bottomRight.setAlignment(Pos.CENTER);
//Alle Komponenten "zusammenfügen"
bottomRight.getChildren().addAll(tabPane, wordText, insertButton);
bottom.getChildren().addAll(canvas, bottomRight);
haupt.getChildren().addAll(top, bottom);
Scene scene = new Scene(haupt, 950,700);
top.getChildren().addAll(buttonSave, buttonShow);
AtomicInteger i = new AtomicInteger(); //Muss benutzt werden, da normaler Integer in Lamba-Expression nicht benutzt werden kann
//Buttonlogik
insertButton.setOnAction((e) ->{
if(!wordText.getText().isEmpty()){
Text text = new Text(wordText.getText());
text.setX(100);
text.setY(200);
canvas.getChildren().add(text);
Text t2 = new Text();
t2.setText(wordText.getText());
t2.setX(10);
t2.setY(25 + 20 * i.getAndIncrement());
contentTab1.getChildren().add(t2);
}
});
window.setScene(scene);
window.setResizable(false);
window.show();
}
Und was kommt dabei heraus, wenn wir den Debugger von NetBeans anwerfen? Probieren wir es aus! Wunderbar, unser Programm erstrahlt im modernen Look einer JavaFX-Anwendung (Abbildung 7). Den Quellcode zum Projekt WordCloud finden hier zum Download.
Mit JavaFX ist man gerüstet, um auch plattformübergreifende Applikationen ansprechend aussehen zu lassen. Die jüngsten Zahlen zur Verwendung zeigen, dass bei neuen Projekten auf diese Technologie gesetzt wird. Man kann das UI komplett im Code bauen. Mit Scene Builder steht aber auch ein UI-Builder zur Verfügung, mit dem das Design auf grafische Art- und Weise erledigt werden kann.
JavaFX braucht kein Schattendasein mehr zu fristen. Die Technologie ist endlich soweit, dass man damit auch „schöne“ Business-Applikationen bauen kann. Aufwändig ist das Migrieren einer Swing-Anwendung nach JavaFX. Der Aufwand und der Erfolg hängen stark davon ab, wie weit die einzelnen Schichten voneinander entkoppelt sind [3]. Für ein neues Projekt sollte man JavaFX auf jeden Fall in Erwägung ziehen.