Einführung in JavaFx

Einführung in JavaFx

1. Einführung

JavaFX ist eine Bibliothek zum Erstellen von Rich-Client-Anwendungen mit Java. It provides an API for designing GUI applications, die auf fast jedem Gerät mit Java-Unterstützung ausgeführt werden.

In diesem Tutorial werden wir uns auf einige der wichtigsten Funktionen konzentrieren und diese behandeln.

2. JavaFX-API

In Java 8, 9 und 10 ist kein zusätzliches Setup erforderlich, um mit der JavaFX-Bibliothek zu arbeiten. Das Projekt wird ab JDK 11 aus dem JDK entfernt.

2.1. Die Architektur

JavaFX uses hardware accelerated graphics pipeline for the rendering, known as Prism. Um die Grafiknutzung vollständig zu beschleunigen, wird außerdem der Software- oder Hardware-Rendering-Mechanismus genutzt, indem internDirectX undOpenGL verwendet werden.

JavaFX has a platform dependent Glass windowing toolkit layer to connect to the native operating system. Es verwendet die Ereigniswarteschlange des Betriebssystems, um die Thread-Nutzung zu planen. Außerdem werden Fenster, Ereignisse und Timer asynchron verarbeitet.

Die EnginesMedia undWeb ermöglichen die Medienwiedergabe und die Unterstützung von HTML / CSS.

Mal sehen, wie diemain structure einer JavaFX-Anwendung aussehen:

image

 

Hier sehen wir zwei Hauptcontainer:

  • Stage is the main container and the entry point of the application. Es stellt das Hauptfenster dar und wird als Argument der Methodestart()übergeben.

  • Scene ist ein Container zum Speichern der UI-Elemente wie Bildansichten, Schaltflächen, Raster, Textfelder.

DieScene können ersetzt oder auf eine andereScene umgeschaltet werden. Dies stellt ein Diagramm hierarchischer Objekte dar, das alsScene-Diagramm bezeichnet wird. Jedes Element in dieser Hierarchie wird als Knoten bezeichnet. Ein einzelner Knoten hat seine ID, seinen Stil, seine Effekte, Ereignisbehandlungsroutinen und seinen Status.

Zusätzlich enthältScene auch die Layoutcontainer, Bilder und Medien.

2.2. Themen

Auf Systemebenethe JVM creates separate threads for running and rendering the application:

  • Prism Rendering-Thread - verantwortlich für das separate Rendern derScene Graph.

  • Anwendungsthread - ist der Hauptthread einer JavaFX-Anwendung. Alle aktiven Knoten und Komponenten sind diesem Thread zugeordnet.

2.3. Lebenszyklus

Die Klassejavafx.application.Applicationhat die folgenden Lebenszyklusmethoden:

  • init() – is called after the application instance is created. Derzeit ist die JavaFX-API noch nicht fertig, sodass wir hier keine grafischen Komponenten erstellen können.

  • start(Stage stage) - Hier werden alle grafischen Komponenten erstellt. Auchthe main thread for the graphical activities starts here.

  • stop() - wird vor dem Herunterfahren der Anwendung aufgerufen; Zum Beispiel, wenn ein Benutzer das Hauptfenster schließt. Es ist nützlich, diese Methode für einige Bereinigungen vor dem Beenden der Anwendung zu überschreiben.

Die statischelaunch()-Methode startet die JavaFX-Anwendung.

2.4. FXML

JavaFX verwendet eine spezielle FXML-Markup-Sprache, um die Ansichtsschnittstellen zu erstellen.

Dies bietet eine XML-basierte Struktur zum Trennen der Ansicht von der Geschäftslogik. XML ist hier besser geeignet, da es ganz natürlich die Hierarchie vonScene Graphdarstellen kann.

Zum Laden der Datei.fxmlverwenden wir schließlich die KlasseFXMLLoader, die zum Objektdiagramm der Szenenhierarchie führt.

3. Anfangen

Um praktisch zu werden, undlet’s build a small application that allows searching through a list of people.

Fügen wir zunächst die ModellklassePersonhinzu, um unsere Domain darzustellen:

public class Person {
    private SimpleIntegerProperty id;
    private SimpleStringProperty name;
    private SimpleBooleanProperty isEmployed;

    // getters, setters
}

Beachten Sie, dass wir zum Abschluss der Werteint, String undboolean die KlassenSimpleIntegerProperty, SimpleStringProperty, SimpleBooleanProperty im Paketjavafx.beans.property verwenden.

Als nächstes erstellen wir die KlasseMain, die die abstrakte KlasseApplicationerweitert:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(
          Main.class.getResource("/SearchController.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        Scene scene = new Scene(page);

        primaryStage.setTitle("Title goes here");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Unsere Hauptklasse überschreibt diestart()-Methode, die der Einstiegspunkt für das Programm ist.

Dann lädtFXMLLoader die Objektgraph-Hierarchie vonSearchController.fxml inAnchorPane hoch.

Nachdem wir ein neuesScene gestartet haben, setzen wir es auf das primäreStage. Wir setzen auch den Titel für unser Fenster undshow() es.

Beachten Sie, dass es nützlich ist, die Methodemain()einzuschließen, um die JAR-Datei ohneJavaFX Launcherausführen zu können.

3.1. FXML-Ansicht

Lassen Sie uns nun tiefer in die XML-Datei vonSearchControllereintauchen.

Für unsere Suchanwendung fügen wir ein Textfeld hinzu, um das Schlüsselwort und die Suchschaltfläche einzugeben:


    

        
            
                

AnchorPane ist hier der Stammcontainer und der erste Knoten der Diagrammhierarchie. Beim Ändern der Fenstergröße wird das untergeordnete Element an seinem Ankerpunkt neu positioniert. The fx: controller attribute wires the Java class with the markup.

Es gibt einige andere integrierte Layouts:

  • BorderPane - unterteilt das Layout in fünf Abschnitte: oben, rechts, unten, links, Mitte

  • HBox – ordnen die untergeordneten Komponenten in einem horizontalen Bereich an

  • VBox – Die untergeordneten Knoten sind in einer vertikalen Spalte angeordnet

  • GridPane - nützlich zum Erstellen eines Rasters mit Zeilen und Spalten

In unserem Beispiel haben wir im horizontalen BereichHBoxLabel verwendet, um Text zu platzieren,TextField für die Eingabe undButton. Mitfx: id markieren wir die Elemente, damit wir sie später im Java-Code verwenden können.

Um sie dann den Java-Feldern zuzuordnen, verwenden wir die Annotation@FXML:

public class SearchController {

    @FXML
    private TextField searchField;
    @FXML
    private Button searchButton;

    @FXML
    private void initialize() {
        // search panel
        searchButton.setText("Search");
        searchButton.setOnAction(event -> loadData());
        searchButton.setStyle("-fx-background-color: #457ecd; -fx-text-fill: #ffffff;");
    }
}

After populating the @FXML annotated fields, initialize() will be called automatically. Hier können wir weitere Aktionen über die UI-Komponenten ausführen, z. B. das Registrieren von Ereignis-Listenern, das Hinzufügen eines Stils oder das Ändern der Texteigenschaft.

Schließlich erzeugt all diese hier beschriebene Logik das folgende Fenster:

image

4. Binding API

Nachdem die visuellen Aspekte behandelt wurden, betrachten wir nun die Bindungsdaten.

Die Bindungs-API stellt einige Schnittstellen bereit, die Objekte benachrichtigen, wenn eine Wertänderung eines anderen Objekts auftritt.

Wir können einen Wert mit der Methodebind()oder durch Hinzufügen von Listenern binden.

Die unidirektionale Bindung bietet eine Bindung nur für eine Richtung:

searchLabel.textProperty().bind(searchField.textProperty());

Hier aktualisiert jede Änderung im Suchfeld den Textwert des Etiketts.

Im Vergleich synchronisiert die bidirektionale Bindung die Werte von zwei Eigenschaften in beide Richtungen.

Die alternative Art, die Felder zu binden, istChangeListeners:

searchField.textProperty().addListener((observable, oldValue, newValue) -> {
    searchLabel.setText(newValue);
});

DieObservable-Schnittstelle ermöglicht es, den Wert des Objekts auf Änderungen zu beobachten.

Um dies zu veranschaulichen, ist die am häufigsten verwendete Implementierung diejavafx.collections.ObservableList<T>-Schnittstelle:

ObservableList masterData = FXCollections.observableArrayList();

Hier benachrichtigt jede Modelländerung, wie das Einfügen, Aktualisieren oder Entfernen der Elemente, die UI-Steuerelemente sofort.

5. Parallelität

Working with the UI components in a scene graph isn’t thread-safe, as it’s accessed only from the Application thread. Das Paketjavafx.concurrent soll beim Multithreading helfen.

Mal sehen, wie wir die Datensuche im Hintergrund-Thread durchführen können:

Task> task = new Task>() {
    @Override
    protected ObservableList call() throws Exception {
        updateMessage("Loading data");
        return FXCollections.observableArrayList(masterData
          .stream()
          .filter(value -> value.getName().toLowerCase().contains(searchText))
          .collect(Collectors.toList()));
    }
};

Hier erstellen wir das Objekt einer einmaligen Aufgabejavafx.concurrent.Taskund überschreiben die Methodecall().

The call() method runs entirely on the background thread and returns the result to the Application thread. Dies bedeutet, dass jede Manipulation der UI-Komponenten innerhalb dieser Methode eine Laufzeitausnahme auslöst.

updateProgress(), updateMessage() kann jedoch aufgerufen werden, um Anwendungs-Thread-Elemente zu aktualisieren. Wenn der Taskstatus in den Status SUCCEEDED übergeht, wird der Ereignishandler vononSucceeded()vom Anwendungsthread aufgerufen:

task.setOnSucceeded(event -> {
    masterData = task.getValue();
    // update other UI components
});

Task istRunnable. Um es zu starten, müssen wir nur ein neuesThread mit dem Parametertask starten:

Thread th = new Thread(task);
th.setDaemon(true);
th.start();

Das FlagsetDaemon(true) zeigt an, dass der Thread nach Abschluss der Arbeit beendet wird.

6. Handhabung des Events

Wir können ein Ereignis als eine Aktion beschreiben, die für die Anwendung interessant sein könnte.

Beispielsweise werden Benutzeraktionen wie Mausklicks, Tastendrücke und Fenstergrößenänderung von der Klassejavafx.event.Eventoder einer ihrer Unterklassen behandelt oder benachrichtigt.

Außerdem unterscheiden wir drei Arten von Ereignissen:

  • InputEvent - Alle Arten von Tasten- und Mausaktionen wieKEY_PRESSED, KEY_TYPED, KEY_RELEASED oderMOUSE_PRESSES, MOUSE_RELEASED

  • ActionEvent - repräsentiert eine Vielzahl von Aktionen wie das Abfeuern vonButton oder das Beenden vonKeyFrame

  • WindowEvent -WINDOW_SHOWING, WINDOW_SHOWN

Zur Veranschaulichung erfasst das folgende Codefragment das Ereignis des Drückens der TasteEnter übersearchField:

searchField.setOnKeyPressed(event -> {
    if (event.getCode().equals(KeyCode.ENTER)) {
        //search and load some data
    }
});

7. Stil

Wir können die Benutzeroberfläche der JavaFX-Anwendung ändern, indem wir ein benutzerdefiniertes Design darauf anwenden.

Standardmäßig verwendet JavaFXmodena.css als CSS-Ressource für die gesamte Anwendung. Dies ist ein Teil derjfxrt.jar.

Um den Standardstil zu überschreiben, können wir der Szene ein Stylesheet hinzufügen:

scene.getStylesheets().add("/search.css");

Wir können auch den Inline-Stil verwenden. So legen Sie beispielsweise eine Stileigenschaft für einen bestimmten Knoten fest:

searchButton.setStyle("-fx-background-color: slateblue; -fx-text-fill: white;");

8. Fazit

Diese kurze Beschreibung behandelt die Grundlagen der JavaFX-API. Wir gingen die interne Struktur durch und stellten die wichtigsten Funktionen der Architektur, des Lebenszyklus und der Komponenten vor.

Als Ergebnis haben wir gelernt, dass wir eine einfache GUI-Anwendung erstellen können.

Und wie immer ist der vollständige Quellcode des Tutorialsover on GitHub verfügbar.