Ein erstes “Hello World” von JavaFX mit Maven

https://bildung.social/@oerinformatik/

https://oer-informatik.de/jfx_02_helloworld_und_aufbau

tl/dr; (ca. 5 min Lesezeit): Aufbau einer “Hello World”-JavaFX App und Analyse der beteiligten Klassen, Objekte und Methoden. Hintergrund zum Aufruf der Methoden launch() und start(), die den Start einer JavaFX-App bilden. Der Artikel ist Teil eines JavaFX-Tutorials. (Zuletzt geändert am 19.11.2023)

Änderungen am Programmcode…

Wir haben in unserem Ausgangsprogramm drei Dateien und eine Ordnerstruktur erzeugt:

  • Die pom.xml legt fest, welche Abhängigkeiten wir laden (z.B. die JavaFX-Module), mit welcher Java-Version wir unser Projekt starten wollen, wie das Projekt und das umgebende Paket heißt und wo die Startklasse zu finden ist. Abhängigkeiten und Java-Version mussten wir gegenüber der Vorlage anpassen.

  • Die Startklasse hört im Beispiel auf den Namen “App.java” und liegt in der Ordnerstruktur, die dem Paketnamen entspricht (src/main/java/de/csbme/ifaxx/myfxproject/App.java). Beides könnten wir in der pom.xml anpassen (tut aber nicht Not). Wir hatten hier zwei Änderungen vorgenommen: in der main()-Methode wurde ein Aufruf ergänzt (launch()) und eine zweite Methode (start()) wurde eingefügt, um die wir uns hier genauer kümmern werden.

  • Die AppTest.java, die unsere Vorlage erzeugt hat, referenziert noch auf die Beziehnungen einer alten jUnit-Version - im einfachsten Fall leeren wir diese Datei bis auf den Klassenrumpf und die Package-Bezeichnung.

Wer eine andere Vorlage verwendet hat, hat ggf. einen andern Startklassennamen, andere Pakete und Dateien wie primary.fxml, secondary.fxml oder module-info.java - die wir hier nicht benötigen - diese können gelöscht werden.

Anpassungen in der Datei App.java

In der pom.xml wurde ja bei der Konfiguration von main.class hinterlegt, wie die Klasse heißt, die unser Artefakt startet (in diesem Fall: unsere Desktop-App App.java).

Maven startet in dieser Klasse eine public static void main(String[] args)-Methode. Für das Grundgerüst benötigen wir also diese statische Methode.

Damit wir nicht alle Methoden selbst implementieren müssen, nutzen wir eine vordefinierte JavaFX-Klasse, von der wir erben: public class App extends Application.

Eine zweite Methode namens start() benötigt JavaFX, um später unser eigentliches Programm aufzunehmen. Das Grundgerüst der App.java sollte also etwa so aussehen:

Jetzt können wir die Platzhalter in der App.java füllen. Die Methode start() ist das Herzstück unseres ersten eigenen JavaFX-Programms. Hieran können wir die Grundlagen eines jeden JavaFX-Programms erkennen. In unserem Ausgangsbeispiel gab es nur zwei Zeilen in dieser Methode (primaryStage.setScene(...); und primaryStage.show()). Wir ersetzen diese beiden Zeilen durch einen etwas detaillierteren und übersichtlicheren Aufruf:

Wir schauen uns die Methode mal von unten nach oben an:

Die Stage erhalten wir als Parameter übergeben, von wem genau schauen wir uns später an. Die Stage ist der Ort, an dem alles angezeigt wird - das Startfenster unseres Programms. Wir zeigen diese am Ende der Methode mit primaryStage.show(); an.

Die Dinge, die wir auf der Bühne anzeigen, nennen wir Scene - also Szenen (primaryStage.setScene(scene);). In unserem Beispiel ist die Scene 300x200 Pixel groß und zeigt etwas an, das hier rootNode genannt wurde (new Scene(rootNode, 300, 250);).

Ein Node ist ein Inhaltselement, das weitere Inhaltselemente enthalten kann (z.B. eine Tabelle, ein Gitter, ein Stapel). In unserem Fall enthält der Stapel (StackPane) nur ein Element, nämlich einen Text (new StackPane(textLeaf);). Diesen Text haben wir in der ersten Zeile der Methode erstellt (Text textLeaf = new Text("Hallo");).

Was jetzt noch fehlt, um ein lauffähiges Programm zu erhalten, sind die fehlenden Importe. Wenn es die IDE nicht alleine schafft, die korrekten Klassen zu finden, dann hilft vielleicht dieser Spickzettel zum Vergleichen:

Wer ruft hier eigentlich wen auf?

Es scheinen bei JavaFX wieder von Zauberhand Dinge zu passieren, die schwer nachvollziehbar sind: In der main()-Methode wird eine launch()-Methode aufgerufen, die nirgends implementiert ist. Stattdessen gibt es eine start()-Methode, die wiederum nirgends aufgerufen wird. Wir müssen hier kurz Licht ins Dunkel bringen, in dem wir uns mal ein UML-Klassendiagramm anschauen:

UML-Klassendiagramm der JavaFX-Klassen App, Application, LauncherImpl
UML-Klassendiagramm der JavaFX-Klassen App, Application, LauncherImpl

Das erste Geheimnis ist schnell gelüftet: die mysteriöse Methode launch()-Methode, die in der main()-Methode aufgerufen wird, ist eine statische Methode der Superklasse Application, von der App erbt.

Das zweite Rätsel bleibt aber: start() ist eine Instanzmethode. Aber an welcher Stelle wird eine Instanz von App gebildet? Und wo wird start() aufgerufen?

Dazu werfen wir ein Blick in ein UML-Sequenzdiagramm, das die Abläufe im Hintergrund etwas erklärt:

UML-Klassendiagramm der JavaFX-Klassen App, Application, LauncherImpl
UML-Klassendiagramm der JavaFX-Klassen App, Application, LauncherImpl
  • Der Benutzer startet Maven, Maven wiederum ruft die main()-Methode der in der pom.xml hinterlegten Klasse (hier: App) auf. Das hatten wir ja bereits entschlüsselt.

  • In dieser Main-Methode wird launch() aufgerufen, eine statische Methode der Superklasse Application. Diese wiederum ruft eine statische Methode einer weiteren Klasse auf (muss man sich nicht merken, der Vollständigkeit halber: sie heißt LauncherImpl):

  • Der Dreh- und Angelpunkt ist die launchApplication()-Methode dieser mysteriösen Klasse (LauncherImpl). Diese Methode erzeugt die Stage, auf der später alles angezeigt wird, instanziiert die Klasse App und ruft schlussendlich die start()-Methode auf, die dann wiederum die Stage selbst anzeigt (show()). Bei Programmende wird hier noch die Methode stop() der App aufgerufen.

Vielleicht war das für jetzt etwas dick aufgetragen. Ich komme jedoch häufig an den Punkt, an dem ich Dinge erst verstehe (und debuggen kann), wenn mir die dahinterliegende Struktur klar geworden ist. Wer noch etwas mehr über die Hintergründe und Realisierungen erfahren will, der kann sich den Quelltext der Superklasse Application sowie der Klasse LauncherImpl unter diesen Links ansehen.

Ausführen des JavaFX-Projekts

Eigentlich haben wir nur den Code umgeschrieben, ohne großartig neue Funktionen zu implementieren. Trotzdem: per Maven/Plugins/javafx/run oder per Konsole können wir das Programm starten:

Nächste Schritte

Ein leeres Projekt ist kein schönes Projekt. Wir brauchen Struktur und dazu den Scenegraph (siehe folgender Artikel).

Dieser Artikel ist ein Teil der Artikelserie zu einer Energiemonitors mit JavaFX.


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: Ein erstes "Hello World" von JavaFX mit Maven” von Hannes Stein, Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/jfx_02_helloworld_und_aufbau veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/javafx/javafx-einstieg. Stand: 19.11.2023.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: