Tutoriel JavaFX: FXML et SceneBuilder

Traduction du tutoriel JavaFX: article FXML et SceneBuilder par Vojtech Ruzicka.

Comment créer une interface graphique avec JavaFX en utilisant le balisage FXML et SceneBuilder.

Tous les articles de la série JavaFX:

  1. Tutoriel JavaFX: Prise en main
  2. Tutoriel JavaFX: Bonjour tout le monde!
  3. Tutoriel JavaFX: FXML et SceneBuilder
  4. Tutoriel JavaFX: dispositions de base
  5. Tutoriel JavaFX: dispositions avancées
  6. Tutoriel JavaFX: style CSS
  7. JavaFX Weaver: intégration des applications JavaFX et Spring Boot

Manière traditionnelle


Dans l'article précédent, nous avons créé une simple application Hello World .

Juste un rappel - le code ressemblait à ceci:

@Override public void start(Stage primaryStage) throws Exception { primaryStage.setTitle("Hello world Application"); primaryStage.setWidth(300); primaryStage.setHeight(200); InputStream iconStream = getClass().getResourceAsStream("/icon.png"); Image image = new Image(iconStream); primaryStage.getIcons().add(image); Label helloWorldLabel = new Label("Hello world!"); helloWorldLabel.setAlignment(Pos.CENTER); Scene primaryScene = new Scene(helloWorldLabel); primaryStage.setScene(primaryScene); primaryStage.show(); } 

Comme vous pouvez le voir, toute l'interface utilisateur est créée en code Java.

Il s'agit d'un exemple très simple, mais à mesure que votre application devient plus complexe, lorsque vous devez entrer plusieurs niveaux de dispositions imbriquées et de nombreux composants, le code résultant peut devenir très difficile à comprendre. Cependant, ce n'est pas tout - dans la même classe, il y a du code qui est responsable de la structure, des effets visuels et du comportement en même temps.

La classe n'a clairement aucune responsabilité. Comparez cela, par exemple, avec l'interface Web, où chaque page a des tâches clairement séparées:

  • HTML est une structure
  • CSS est des effets visuels
  • JavaScript est un comportement

Présentation de FXML


Évidemment, avoir tout le code en un seul endroit n'est pas une bonne idée. Vous devez le structurer d'une manière ou d'une autre afin qu'il soit plus facile à comprendre et à rendre plus facile à gérer.

En réalité, il existe de nombreux modèles de conception pour cela. En règle générale, vous vous retrouvez avec une option «Model-View-Whats» - c'est quelque chose comme «Model View Controller», «Model View Presenter» ou «Model View ViewModel».

Vous pouvez passer des heures à discuter des avantages et des inconvénients des différentes options - ne le faisons pas ici. Plus important encore, avec JavaFx, vous pouvez utiliser n'importe lequel d'entre eux.

Cela est possible car en plus de la conception procédurale de votre interface utilisateur, vous pouvez utiliser un balisage XML déclaratif.

Il s'avère que la structure hiérarchique XML est un excellent moyen de décrire la hiérarchie des composants dans l'interface utilisateur. Le HTML fonctionne plutôt bien, non?

Le format XML spécifique à JavaFX est appelé FXML. Dans celui-ci, vous pouvez définir tous les composants d'application et leurs propriétés, ainsi que les associer au contrôleur, qui est responsable de la gestion des interactions.

Télécharger des fichiers FXML


Alors, comment pouvons-nous changer notre méthode de lancement pour travailler avec FXML?

 FXMLLoader loader = new FXMLLoader(); URL xmlUrl = getClass().getResource("/mainScene.fxml"); loader.setLocation(xmlUrl); Parent root = loader.load(); primaryStage.setScene(new Scene(root)); primaryStage.show(); 

Ici, root représente le composant racine de votre interface utilisateur, d'autres composants y sont imbriqués.

La méthode de chargement a une valeur de retour générique, vous pouvez donc spécifier un type spécifique, pas Parent . Ensuite, vous avez accès à des méthodes orientées composants. Cependant, cela rend votre code plus fragile. Si vous modifiez le type de composant racine dans votre FXML, l'application peut cesser de fonctionner au moment de l'exécution, mais il n'y aura aucune erreur lors de la compilation. En effet, il existe maintenant une incompatibilité du type déclaré dans votre FXML et dans le chargeur Java FXML.

Créer un fichier FXML


Nous savons maintenant comment charger le fichier FXML, mais nous devons encore le créer. Le fichier doit avoir l'extension .fxml. Dans un projet Maven, vous pouvez placer ce fichier dans le dossier des ressources ou FXMLLoader peut le télécharger à partir d'une URL externe.

Après avoir créé le fichier, entrez la déclaration XML dans sa première ligne:

 <?xml version="1.0" encoding="UTF-8"?> 

Importer


Avant d'ajouter des composants individuels à un fichier, vous devez vous assurer qu'ils sont correctement reconnus. Pour ce faire, ajoutez des instructions d'importation. Ceci est très similaire à l'importation dans les classes Java. Vous pouvez importer des classes individuelles ou utiliser des caractères génériques comme d'habitude. Regardons un exemple de section d'importation:
 <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> 

La bonne nouvelle est qu'au lieu d'ajouter toutes les instructions d'importation manuellement, votre IDE devrait vous aider à ajouter l'importation comme à les ajouter aux classes Java.

Ajout de composants


Il est maintenant temps d'ajouter quelques composants. Dans un article précédent, nous avons appris que chaque scène ne peut avoir qu'un seul composant enfant. Pour commencer, ajoutons une simple étiquette:

 <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Label?> <!--      --> <Label>Hello World!</Label> 

Bien sûr, l'étiquetage en tant que composant racine n'est pas un exemple très réaliste. Il est généralement préférable d'utiliser une sorte de disposition (layout), qui est un conteneur pour plusieurs composants et organise leur disposition. Nous couvrirons les dispositions plus tard dans cette série, mais pour l'instant, utilisons simplement une VBox simple qui place ses enfants verticalement les uns sur les autres.

 <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Label?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Button?> <VBox> <Label text="Hello world!"/> <Label text="This is a simple demo application."/> <Button text="Click me!"/> </VBox> 

Espace de noms FX


Il existe quelques éléments et attributs FXML qui ne sont pas disponibles par défaut. Vous devez ajouter un espace de noms FXML pour les rendre disponibles. Il doit être ajouté au composant racine:

 <?xml version="1.0" encoding="UTF-8"?> ... <VBox xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"> ... </VBox> 

Vous pouvez maintenant utiliser les nouveaux éléments de l'espace de noms fx. Essayons d'ajouter des identifiants uniques à nos composants:

 <Label fx:id="mainTitle" text="Hello world!"/> 

L'attribut fx: id est un identifiant unique pour un composant qui peut être utilisé pour faire référence à un composant provenant d'autres parties de notre FXML et même de notre contrôleur.

Scripts


Notre application est toujours statique. Il y a plusieurs étiquettes et un bouton, mais l'application ne fait rien de dynamique.

Répondons au clic de notre bouton et changeons le titre de «Click me!» En «Click me again!».

La première chose à faire est d'ajouter un gestionnaire d'événements onAction pour notre bouton.

 <Button fx:id="mainButton" text="Click me!" onAction="buttonClicked()"/> 

Faites attention à fx: id, c'est l'identifiant qui sera utilisé plus tard pour faire référence au bouton.

Vous devez maintenant fournir une fonction qui sera appelée pour gérer l'événement. Il peut être défini à l'intérieur de la balise fx: script. L'important est que vous puissiez utiliser différents langages pour écrire un script, JavaScript, Groovy ou Clojure. Regardons un exemple en JavaScript:



Notez que nous nous référons à notre composant Button en utilisant l'identifiant mainButton, qui a été déclaré comme ceci:

 fx:id = "mainButton" 

Vous devez également indiquer le langage de script que vous utilisez dans le fichier FXML:

 <?language javascript?> 

Regardons le texte intégral de l'exemple:



Dois-je l'utiliser?


L'exemple ci-dessus montre comment référencer des composants à l'aide de fx: id et comment ajouter un comportement simple à l'aide d'un script JavaScript. Est-ce vraiment ce que vous devriez faire?

Dans la plupart des cas, la réponse est non. Il y a plusieurs problèmes avec cette approche. La raison pour laquelle FXML a été introduit était une séparation des intérêts - pour séparer la structure et le comportement de l'interface utilisateur. Dans ce script, le comportement fusionné avec la structure de l'interface utilisateur est à nouveau renvoyé. De plus, comme nous ne travaillons plus avec le code Java, mais avec XML, toutes les vérifications de code au moment de la compilation et la sécurité des types ont été perdues. Désormais, tous les problèmes de l'application seront détectés au moment de l'exécution et non au moment de la compilation. L'application est devenue très fragile et sujette aux erreurs.

Ajout d'un contrôleur


Alors, que peut-on faire pour obtenir une séparation claire des intérêts? Vous pouvez lier le contrôleur à notre fichier FXML. Un contrôleur est une classe Java chargée de gérer le comportement et l'interaction utilisateur dans une application. De cette façon, vous pouvez renvoyer des vérifications de sécurité de type et de compilation.

Le contrôleur est un POJO, il ne doit ni étendre ni implémenter quoi que ce soit, ni avoir d'annotations spéciales.

Comment puis-je associer une classe de contrôleur à notre FXML? Il existe essentiellement deux options.

En Java


Vous pouvez créer vous-même une instance du contrôleur ou utiliser toute autre méthode de création d'une instance, telle qu'une injection de dépendance. Ensuite, téléchargez simplement votre FXMLLoader .

 FXMLLoader loader = new FXMLLoader(); loader.setController(new MainSceneController()); 

Dans FXML


Vous pouvez spécifier la classe de votre contrôleur en tant qu'attribut fx: controller , qui doit se trouver dans le composant racine.

 <VBox xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.vojtechruzicka.MainSceneController"> ... </VBox> 

Si vous déclarez votre classe Controller dans FXML, elle est automatiquement créée pour vous. Cette approche a une limitation - dans le contrôleur, vous devez créer un constructeur sans arguments pour faciliter la création d'une nouvelle instance de la classe Controller.

Pour accéder à une instance d'un contrôleur créé automatiquement, vous pouvez utiliser le chargeur FXML:

 FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource("/mainScene.fxml")); MainSceneController controller = loader.getController(); 

Appel des méthodes du contrôleur


Maintenant que vous avez un contrôleur, vous pouvez supprimer le script et implémenter la logique pour appuyer sur les boutons directement dans le contrôleur:

 public class MainSceneController { public void buttonClicked() { System.out.println("Button clicked!"); } } 

L'étape suivante consiste à enregistrer l'appel de cette méthode en tant que gestionnaire d' événement onAction de notre bouton. Pour faire référence aux méthodes de notre contrôleur, nous devons utiliser le signe # devant le nom de la méthode:

 <VBox xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.vojtechruzicka.MainSceneController"> <Label fx:id="mainTitle" text="Hello world!"/> <Label fx:id="subTitle" text="This is a simple demo application."/> <Button fx:id="mainButton" text="Click me!" onAction="#buttonClicked"/> </VBox> 

Lorsqu'un bouton est cliqué, il appelle la méthode MainSceneController.buttonClicked () . Gardez à l'esprit que cela ne fonctionne que si la méthode est déclarée publique. Si le modificateur d'accès est plus strict, vous devez annoter la méthode avec l'annotation @FXML .

 @FXML private void buttonClicked() { System.out.println("Button clicked!"); } 

Incorporation de composants dans un contrôleur


Jusqu'à présent, nous imprimons simplement sur la console. Que se passe-t-il si nous voulons changer à nouveau le texte de notre bouton en « Cliquez-moi à nouveau »? Comment pouvons-nous obtenir des liens vers des composants dans notre contrôleur?

Heureusement, c'est facile. Rappelez-vous ces attributs fx: id ?

 <Button fx:id="mainButton" text="Click me!" onAction="#buttonClicked"/> 

JavaFX essaie de faire correspondre automatiquement les composants avec fx: id avec les champs définis dans votre contrôleur avec le même nom.

Supposons que nous ayons un bouton décrit ci-dessus avec

 fx:id="mainButton" 

JavaFX essaie d'injecter l'objet bouton dans votre contrôleur dans un champ appelé mainButton :

 public class MainSceneController { //    fx:id = "mainButton" @FXML private Button mainButton; } 

Comme dans les méthodes précédentes, vos champs doivent être publics ou annotés @FXML .

Maintenant que nous avons un lien vers notre bouton, nous pouvons facilement changer son texte:

 public class MainSceneController { @FXML private Button mainButton; @FXML private void buttonClicked() { mainButton.setText("Click me again!"); } } 

Constructeur de scène


L'écriture de votre structure GUI en XML peut être plus naturelle qu'en Java (surtout si vous êtes familier avec HTML). Cependant, ce n'est toujours pas très pratique. La bonne nouvelle est qu'il existe un outil officiel appelé Scene Builder qui vous aidera à créer l'interface utilisateur. En bref, il s'agit d'un éditeur graphique pour votre interface graphique.



L'éditeur a trois domaines principaux:

  1. La partie gauche affiche les composants disponibles qui peuvent être glissés vers la partie centrale. Il contient également une hiérarchie de tous les composants de votre interface utilisateur, afin que vous puissiez facilement y naviguer.
  2. La partie centrale est votre application affichée en fonction de votre fichier FXML.
  3. À droite, l'inspecteur de composants actuel. Ici, vous pouvez modifier diverses propriétés du composant actuel sélectionné. Tout composant sélectionné au milieu de la hiérarchie est affiché dans l'inspecteur.

Autonome


Scene Builder peut être téléchargé en tant qu'application autonome pouvant être utilisée pour modifier des fichiers FXML.

Intégration avec IntelliJ IDEA


Alternativement, Scene Builder offre une intégration avec l'IDE.

Dans IntelliJ IDEA, vous pouvez cliquer avec le bouton droit sur n'importe quel fichier FXML, puis sélectionner l'option de menu Ouvrir dans SceneBuilder.

Alternativement, IntelliJ IDEA intègre SceneBuilder directement dans l'IDE. Si vous ouvrez le fichier FXML dans IDEA, deux onglets apparaîtront en bas de l'écran

  • Texte
  • Scénographe

Pour chaque fichier FXML, vous pouvez facilement basculer entre l'édition du fichier FXML directement ou via SceneBuilder.



Dans IntelliJ IDEA, vous pouvez configurer l'emplacement de l'exécutable SceneBuilder:

Settings → Languages & Frameworks → JavaFX → Path to SceneBuilder

Et ensuite


Dans le prochain article de notre série, nous aborderons quelques dispositions de base qui peuvent être utilisées pour organiser les composants d'une application GUI dans JavaFX.

Source: https://habr.com/ru/post/fr474982/


All Articles