Historisches
Im Jahr 2001 erschien die Version JavaFX 2.0. Sie enthielt eine eigene Skriptsprache und war kein großer Erfolg. Nun wurde FX von grundauf erneuert und läuft unter dem Namen Java FX 8. Das alte JavaFX Script entfällt und Hardware-Rendering wird unterstützt. Seit Java 7 ist JavaFX nun in der Standard-Edition (JSE) integriert. Langfristig soll JavaFX Swing ablösen.Neu gegenüber Swing ist beispielsweise, dass die Gestaltung von Eingabemasken durch FXML, eine XML-basierte Beschreibungssprache erfolgen kann. Für die Gestaltung von Eingabemasken wird CSS unterstützt.
Eclipse und JavaFX
Für eclipse gibt es das Plugin e(fx)clipse. Damit lassen sich auch spezielle Java-FX-Projekte erzeugen.
Java-Versionen für Java FX
Java 8 bringt bereits eine saubere FX-Umgebung mit. Wird Java 7 verwendet, muss die externe Jar jfxrt.jar eingebunden werden, die sich im Verzeichnis lib der JRE befindet.Weiterer Link zu dem Thema:
Eine JavaFX-Applikation
Eine JavaFX-Applikation erweitert die Klasse javafx.application.Application. Das Programm wird nicht durch die static-Methode main() gestartet, wie andere Java-Applikationen. Stattdessen überschreibt eine FX-Awendung die Methode start(), der als Parameter eine Stage übergeben wird.Die Stage repräsentiert das Hauptfenster der Anwendung. Sie stellt einen User-Interface-Container zur Verfügung, welcher eine Scene enthält.
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class FirstFX extends Application { public static void main(String[] args) { launch(args); // sorgt indirekt für den Aufruf von start } @Override public void start(Stage hauptStage) { Button button = new Button(); // Damit etwas da ist button.setText("Drück mich!"); // Bereite die Reaktion auf den Button-Klick vor button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("Hab' Dich auch lieb!"); } }); // Alles zusammensetzen StackPane layoutContainer = new StackPane(); // Layout-Container layoutContainer.getChildren().add(button); Scene scene = new Scene(layoutContainer, 300, 250); // scene beschreibt den Inhalt hauptStage.setScene(scene); hauptStage.show(); // fehlt das, sieht man gar nichts } }
Werden die Parameter für Breite und Höhe im Konstruktor von Scene nicht angegeben, wird der zur Verfügung stehende Bereich verwendet.
Ausrichten von Elementen mit Pane
Ein Pane ist ein Brett, auf dem Elemente angeordnet werden können. Die Scene von Haus aus nur ein Element auf. Dieses Element ist typischerweise ein Pane, auf dem weitere Panes für die Anordnung der Elemente sorgen.
HBox und VBox | Stapelt die Elemente einzeln neben- bzw. übereinander |
FlowPane | Füllt Reihe auf und bricht bei Platzmangel um |
GridPane | Im Raster angeordnet, typischerweise für Dialoge |
BorderPane | Randelemente mit großem Zentrum: Top, Bottom, Left und Right. |
StackPane | Elemente werden an derselben Position aufeinander gelegt. |
TilePane | Ordnet die enthaltenen Elemente in gleichbleibend großem Layout. |
Eventhandling
Wenn der Button gedrückt wird, soll irgendetwas passieren. Dazu besitzt so ein Button die Methode setOnAction(). Der Parameter dieser Methode ist ein EventHandler. Ein Objekt der Klasse EventHandler wird auf das Ereignis reagieren und entsprechende Aktionen einleiten.Der EventHandler kann als eigene Klasse implementiert werden, die sich von EventHandler herleitet und die Methode handle() implementiert. Auf diese Weise wird der Aufbau des Dialogs und die Verarbeitung der Inhalte sauber getrennt.
Bei kleineren Dialogen kann es übersichtlicher sein, alles in einem zu machen und die Klasse, die den Dialog aufbaut auch gleich das Interface EventHandler implementieren zu lassen. Dann wird als EventHandler die eigene Klasse this angegeben. Das folgende Beispiel implementiert den EventHandler für das ActionEvent.
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class FirstFX extends Application implements EventHandler<ActionEvent> { public static void main(String[] args) { launch(args); // sorgt indirekt für den Aufruf von start } @Override public void handle(ActionEvent event) { System.out.println("Hab' Dich auch lieb!"); } @Override public void start(Stage hauptStage) { // hauptStage.setTitle("Erster Versuch in JavaFX"); Button button = new Button(); // Damit etwas da ist button.setText("Drück mich!"); // Bereite die Reaktion auf den Button-Klick vor button.setOnAction(this); // Alles zusammensetzen BorderPane layoutContainer = new BorderPane(); // Layout-Container layoutContainer.setBottom(button); Scene scene = new Scene(layoutContainer); // scene beschreibt den Inhalt hauptStage.setScene(scene); hauptStage.show(); // fehlt das, sieht man gar nichts } }
Wenn die Ereignisse direkt am Kontrollelement bearbeitet werden sollen, kann man auch die Klasse EventHandler direkt im Parameter der Funktion setOnAction() erzeugen und implementieren.
Die Konstruktion, im Parameter von setOnAction() ein anonymes Objekt zu erzeugen, das eine Handle-Funktion implementiert, kann mithilfe von Lambda, das ja seit Java 8 auch zur Verfügung steht, erheblich verkürzt werden. Statt dieser Zeilen:
button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("Hab' Dich auch lieb!"); } });funktioniert folgende Zeile genauso gut:
button.setOnAction(event -> System.out.println("Hab' Dich auch lieb!"));Es ist auch möglich, eine eigene Klasse für die Events zu schreiben. Sie muss EventHandler implementieren und dazu die Methode handle überschreiben.
public class Ereignis implements EventHandlerDamit die Applikation das Event verarbeiten kann, muss sie die Methode handle() im EventHandler implementieren. Deren Parameter enthält die Informationen rund um das Ereignis.{ ... @Override public void handle(ActionEvent event) { ... } }
Wer war's?
Die Methode handle erfährt durch ihren Parameter die Randbedinungen eines Ereignisses. So kann die Methode feststellen, welcher Button geklickt wurde. Solange es nur einen Button gibt, ist diese Information nur mäßig spannend. Wird aber eine zentrale Ereignismethode für mehrere Kontrollelemente verwendet, will man einfach wissen, wer der Täter ist. Diese Frage beantwortet die Methode getSource().@Override public void handle(ActionEvent event) { if (event.getSource()==okButton) { System.out.println("Action!"); } else if (event.getSource()==cancelButton) { System.out.println("War alles nur Spaß!"); } }
Kontrollelemente
Die Kontrollelemente ermöglichen den Dialog mit dem Anwender. Durch Eingabefelder, Buttons und andere Elemente kann er seine Wünsche an das Programm stellen.Label
Ein Label zeigt einen Text an. Es dient der Beschriftung von Dialogen, aber auch, um Ergebnisse anzuzeigen. Der Label an sich ist passiv. Es fängt keine Ereignisse, sondern ist einfach nur schön.Button
Buttons nehmen einen Klick entgegen und führen fast immer zu Aktionen.TextField
Ein Eingabefeld hat den Zweck, dass der Anwender auch mal einen Namen, eine Zahl oder eine sonstige Textzeile eingeben kann.
CheckBox und ToggleButton
Diese beiden Abarten des Buttons dienen dazu den logischen Status durch einen
Haken (CheckBox) oder durch Tiefe (ToggleButton) darzustellen und zu erfassen.
RadioButton
Ein RadioButton entspricht in seiner Funktion einem ToggleButton.
Seine Besonderheit ist, dass er in einer ToggleGroup organisiert ist.
Von allen zu einer ToggleGroup organisierten RadioButtons kann nur einer
aktiviert sein.
ComboBox
Bei der ComboBox handelt es sich um eine Klappliste, aus deren Elementen der
Anwender eines auswählen kann. Zur Füllung der Klappliste wird eine
ObservableList eingesetzt.
ListView
Die ListView wird wie ComboBox und ChoiceBox mit einer
ObservableList gefüllt.
Sie nimmt naturgemäß mehr Raum ein und dient nicht in erster Linie der
Auswahl sondern der Darstellung von Daten.
TableView
Der TableView entspricht einer ListView, verfügt aber darüber hinaus auch noch Spaltenüberschriften.Menüs
Einsatz von CSS in Java FX
Jedem Element kann mit der Methode setStyle() eine Eigenschaft übergeben werden.button.setStyle("-fx-background-color: yellow;");Für JavaFX sind eigene Style Sheets definiert. Beispielsweise:
- -fx-font-size: 20px;
- -fx-background-color: white;
- -fx-background-color: linear-gradient(gray, darkgray);
- -fx-fill:linear-gradient(orange, orangered);
- -fx-padding: 15;
- -fx-spacing: 10;
- -fx-background-image: url("bg.jpg");
- -fx-background-size: 270, 160;
- -fx-background-repeat: no-repeat;
textfeld.setId("text"); rahmen.setId("root");Im CSS kann nun mit #text auf das Element textfeld zugegriffen werden und mit #root auf das Element rahmen.
Um eine externe CSS zuzugreifen, wird die Scene folgende Methode aufgerufen.
scene.getStylesheets().add(this.getClass().getResource("text.css") .toExternalForm());