Introduction à JavaFx

Introduction à JavaFx

1. introduction

JavaFX est une bibliothèque permettant de créer des applications client riches avec Java. It provides an API for designing GUI applications qui s'exécutent sur presque tous les périphériques prenant en charge Java.

Dans ce didacticiel, nous allons nous concentrer et couvrir certaines de ses principales capacités et fonctionnalités.

2. API JavaFX

En Java 8, 9 et 10, aucune configuration supplémentaire n'est nécessaire pour commencer à utiliser la bibliothèque JavaFX. Le projet sera supprimé du JDK à partir de JDK 11.

2.1. Architecture

JavaFX uses hardware accelerated graphics pipeline for the rendering, known as Prism. De plus, pour accélérer pleinement l’utilisation des graphiques, il exploite le mécanisme de rendu logiciel ou matériel, en utilisant en interneDirectX etOpenGL.

JavaFX has a platform dependent Glass windowing toolkit layer to connect to the native operating system. Il utilise la file d’attente d’événements du système d’exploitation pour planifier l’utilisation des threads. En outre, il gère de manière asynchrone les fenêtres, les événements et les minuteries.

Les moteursMedia etWeb permettent la lecture multimédia et le support HTML / CSS.

Voyons à quoi ressemblent lesmain structure d'une application JavaFX:

image

 

Ici, nous remarquons deux conteneurs principaux:

  • Stage is the main container and the entry point of the application. Il représente la fenêtre principale et est passé en argument de la méthodestart().

  • Scene est un conteneur pour contenir les éléments de l'interface utilisateur, tels que les vues d'image, les boutons, les grilles, les zones de texte.

LesScene peuvent être remplacés ou basculés sur un autreScene. Cela représente un graphique d'objets hiérarchiques, appelé graphiqueScene. Chaque élément de cette hiérarchie est appelé un nœud. Un seul nœud a son ID, son style, ses effets, ses gestionnaires d’événements, son état.

De plus, leScene contient également les conteneurs de mise en page, les images, les médias.

2.2. Les fils

Au niveau du système,the JVM creates separate threads for running and rendering the application:

  • Fil de rendu dePrism - responsable du rendu desScene Graph séparément.

  • Fil d'application - est le fil principal de toute application JavaFX. Tous les nœuds et composants actifs sont attachés à ce fil.

2.3. Cycle de la vie

La classejavafx.application.Application a les méthodes de cycle de vie suivantes:

  • init() – is called after the application instance is created. À ce stade, l'API JavaFX n'est pas encore prête, nous ne pouvons donc pas créer de composants graphiques ici.

  • start(Stage stage) - tous les composants graphiques sont créés ici. Aussi,the main thread for the graphical activities starts here.

  • stop() - est appelé avant l'arrêt de l'application; par exemple, lorsqu'un utilisateur ferme la fenêtre principale. Il est utile de remplacer cette méthode pour un certain nettoyage avant l'arrêt de l'application.

La méthode statiquelaunch() démarre l'application JavaFX.

2.4. FXML

JavaFX utilise un langage de balisage FXML spécial pour créer les interfaces de vue.

Ceci fournit une structure basée sur XML pour séparer la vue de la logique métier. XML est plus approprié ici, car il est capable de représenter tout naturellement une hiérarchieScene Graph.

Enfin, pour charger le fichier.fxml, nous utilisons la classeFXMLLoader, qui aboutit au graphe d'objets de la hiérarchie de la scène.

3. Commencer

Pour être pratique, etlet’s build a small application that allows searching through a list of people.

Tout d'abord, ajoutons une classe de modèlePerson - pour représenter notre domaine:

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

    // getters, setters
}

Remarquez comment, pour regrouper les valeursint, String etboolean, nous utilisons les classesSimpleIntegerProperty, SimpleStringProperty, SimpleBooleanProperty dans le packagejavafx.beans.property.

Ensuite, créons la classeMain qui étend la classe abstraiteApplication:

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);
    }
}

Notre classe principale remplace la méthodestart(), qui est le point d'entrée du programme.

Ensuite, leFXMLLoader charge la hiérarchie du graphe d'objets deSearchController.fxml dans lesAnchorPane.

Après avoir démarré un nouveauScene, nous le définissons sur leStage primaire. Nous avons également défini le titre de notre fenêtre etshow() il.

Notez qu'il est utile d'inclure la méthodemain() pour pouvoir exécuter le fichier JAR sans lesJavaFX Launcher.

3.1. Vue FXML

Examinons maintenant plus en détail le fichier XML deSearchController.

Pour notre application de recherche, nous allons ajouter un champ de texte pour saisir le mot-clé et le bouton de recherche:


    

        
            
                

AnchorPane est ici le conteneur racine et le premier nœud de la hiérarchie du graphe. Lors du redimensionnement de la fenêtre, il repositionnera l'enfant à son point d'ancrage. The fx: controller attribute wires the Java class with the markup.

Il existe d'autres mises en page intégrées disponibles:

  • BorderPane - divise la mise en page en cinq sections: haut, droite, bas, gauche, centre

  • HBox – organise les composants enfants dans un panneau horizontal

  • VBox – les nœuds enfants sont disposés dans une colonne verticale

  • GridPane - utile pour créer une grille avec des lignes et des colonnes

Dans notre exemple, à l'intérieur du panneau horizontalHBox, nous avons utilisé unLabel pour placer le texte,TextField pour l'entrée et unButton. Avecfx: id, nous marquons les éléments afin de pouvoir les utiliser plus tard dans le code Java.

Ensuite, pour les mapper aux champs Java - nous utilisons l'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. Ici, nous sommes en mesure d'effectuer d'autres actions sur les composants de l'interface utilisateur, comme l'enregistrement des écouteurs d'événements, l'ajout de style ou la modification de la propriété de texte.

Enfin, toute la logique décrite ici produira la fenêtre suivante:

image

4. Binding API

Maintenant que les aspects visuels sont traités, commençons à examiner les données de liaison.

L'API de liaison fournit des interfaces qui avertissent les objets lorsqu'un changement de valeur d'un autre objet se produit.

Nous pouvons lier une valeur en utilisant la méthodebind() ou en ajoutant des écouteurs.

La liaison unidirectionnelle fournit une liaison pour une seule direction:

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

Ici, tout changement dans le champ de recherche mettra à jour la valeur de texte de l'étiquette.

En comparaison, la liaison bidirectionnelle synchronise les valeurs de deux propriétés dans les deux sens.

La manière alternative de lier les champs estChangeListeners:

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

L'interfaceObservable permet d'observer la valeur de l'objet pour les changements.

Pour illustrer cela, l'implémentation la plus couramment utilisée est l'interfacejavafx.collections.ObservableList<T>:

ObservableList masterData = FXCollections.observableArrayList();

Ici, tout changement de modèle, comme l'insertion, la mise à jour ou la suppression d'éléments, notifiera immédiatement les contrôles de l'interface utilisateur.

5. Simultanéité

Working with the UI components in a scene graph isn’t thread-safe, as it’s accessed only from the Application thread. Le packagejavafx.concurrent est là pour vous aider avec le multithreading.

Voyons comment nous pouvons effectuer la recherche de données dans le fil de discussion en arrière-plan:

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()));
    }
};

Ici, nous créons un objet tâche uniquejavafx.concurrent.Task et remplaçons la méthodecall().

The call() method runs entirely on the background thread and returns the result to the Application thread. Cela signifie que toute manipulation des composants de l'interface utilisateur dans cette méthode lèvera une exception d'exécution.

Cependant,updateProgress(), updateMessage() peut être appelé pour mettre à jour les éléments de thread d'application. Lorsque l'état de la tâche passe à l'état SUCCEEDED, le gestionnaire d'événementsonSucceeded() est appelé à partir du thread d'application:

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

LeTask estRunnable, donc pour le démarrer nous avons juste besoin de démarrer un nouveauThread avec le paramètretask:

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

L'indicateursetDaemon(true) indique que le thread se terminera une fois le travail terminé.

6. Gestion des événements

Nous pouvons décrire un événement comme une action susceptible d'intéresser l'application.

Par exemple, les actions utilisateur telles que les clics de souris, les pressions de touches, le redimensionnement de la fenêtre sont gérées ou notifiées par la classejavafx.event.Event ou l'une de ses sous-classes.

Nous distinguons également trois types d’événements:

  • InputEvent - tous les types d'actions de touches et de souris commeKEY_PRESSED, KEY_TYPED, KEY_RELEASED ouMOUSE_PRESSES, MOUSE_RELEASED

  • ActionEvent - représente une variété d'actions comme déclencher unButton ou terminer unKeyFrame

  • WindowEvent -WINDOW_SHOWING, WINDOW_SHOWN

Pour démontrer, le fragment de code ci-dessous détecte l'événement consistant à appuyer sur la toucheEnter sur lessearchField:

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

7. Style

Nous pouvons modifier l'interface utilisateur de l'application JavaFX en lui appliquant un design personnalisé.

Par défaut, JavaFX utilisemodena.css comme ressource CSS pour l'ensemble de l'application. Ceci fait partie desjfxrt.jar.

Pour remplacer le style par défaut, nous pouvons ajouter une feuille de style à la scène:

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

Nous pouvons également utiliser le style inline; Par exemple, pour définir une propriété de style pour un nœud spécifique:

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

8. Conclusion

Cette brève description couvre les bases de l'API JavaFX. Nous avons examiné la structure interne et présenté les fonctionnalités clés de son architecture, de son cycle de vie et de ses composants.

En conséquence, nous avons appris et sommes maintenant en mesure de créer une application graphique simple.

Et, comme toujours, le code source complet du tutoriel est disponibleover on GitHub.