12.8Deklarative Oberflächen mit FXML
Den Szenegraphen über Java-Programmcode aufzubauen, ist eine Möglichkeit, doch JavaFX erlaubt es auch, die Objekte über XML zu konfigurieren, in so genannten FXML-Dateien. Das macht es viel einfacher, grafische Oberflächen über GUI-Builder aufzubauen und sauber das Layout (was) vom Code (wie) zu trennen.
Die hierarchische Struktur von XML passt natürlich prima zu der Hierarchie, die es bei grafischen Oberflächen gibt: Ein Fenster enthält Container, die wiederum Elemente enthalten usw. Für unser kleines Beispiel soll eine Oberfläche drei Elemente bieten: eine Beschriftung, ein Textfeld und eine Schaltfläche. Drückt der Anwender die Schaltfläche, soll der Text im Textfeld in Großbuchstaben konvertiert werden.
FXML-Datei
Die XML-Datei sieht so aus:
Listing 12.12covert2UpperCase.fxml
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<HBox xmlns:fx="http://javafx.com/fxml"
fx:controller="com.tutego.insel.javafx.ButtonController">
<children>
<Label text="Eingabe: " />
<TextField fx:id="input" />
<Button text="Konvertiere" onAction="#convertAction" />
</children>
</HBox>
Die Hierarchie ist gut zu erkennen. Die interessanten Dinge sind andere:
Zu Beginn gibt es eine Art import-Anweisung, um Typnamen nicht voll qualifizieren zu müssen. Die Typen in FXML (etwa HBox, Label, …) heißen genauso wie die Klassennamen. Natürlich könnten auch eigene Klassen über <?import> bekannt gemacht werden.
HBox hat zwei Attribute: Das erste, xmlns:fx, deklariert den Namensraum fx in der XML-Datei. Dieses Attribut ist keine spezifische Eigenschaft der HBox, sondern würde bei allen XML-Wurzelelementen genutzt werden. Das zweite Attribut spezifiziert den Controller, der später die Ereignisbehandlung für den Klick übernimmt.
Das TextField bekommt mit dem Attribut id eine ID zugewiesen, unter der das Textfeld später erfragt werden kann. JavaFX geht noch einen Schritt weiter und bildet das Objekt mit der ID automatisch auf ein Attribut der Controller-Klasse ab. Label und Schaltfläche brauchen keine IDs, da sie nicht erfragt werden müssen.
Das Attribut onAction der Schaltfläche referenziert Programmcode, der immer aufgerufen wird, wenn die Schaltfläche angeklickt wird. Hier kann direkt Java-Quellcode stehen, oder, wie in unserem Fall, ein # und der Name einer Methode, die in einem Controller deklariert werden muss. Den Klassenamen des Controllers haben wir am Wurzelelement deklariert.
Controller-Klasse
Die Ereignisbehandlung ist komplett aus der FXML-Datei rausgezogen und wandert in Controller-Klassen. Die eigene Klasse ButtonController, die voll qualifiziert bei fx:controller genannt wurde, enthält:
Listing 12.13com/tutego/insel/javafx/ButtonController.java
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class ButtonController
{
@FXML
private TextField input;
@FXML
protected void convertAction( ActionEvent event )
{
input.setText( input.getText().trim().toUpperCase() );
}
}
Drei Dinge springen ins Auge:
Die Controller-Klasse erweitert keine Schnittstelle.
Die Annotation @FXML sagt, dass der Verweis auf das TextField-Objekt aus dem Szenegraphen in die Variable input injiziert werden soll.
Da in der FXML-Datei an der Schaltfläche ein onAction="#convertAction" steht, muss das einer Methode zugeordnet werden. Die Annotation @FXML an der Methode unter dem Namen convertAction stellt diese Beziehung her.
Haupt-Anwendung
Das Hauptprogramm ist nun relativ einfach:
Listing 12.14com/tutego/insel/javafx/FXMLDemo.java, start()
public void start( Stage stage ) throws Exception {
Parent p = FXMLLoader.load( getClass().getResource( "covert2UpperCase.fxml" ) );
stage.setScene( new Scene( p, 500, 400 ) );
stage.show();
}
Weitere Informationen liefert http://download.java.net/jdk8/jfxdocs/javafx/fxml/doc-files/ introduction_to_fxml.html.