FAQ JavaFXConsultez toutes les FAQ
Nombre d'auteurs : 4, nombre de questions : 507, dernière mise à jour : 2 novembre 2016 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur le forum JavaFX de http://java.developpez.com ainsi que l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- 9.14.1. Contrôleur (8)
- 9.14.2. SceneBuilder (5)
- Qu'est-ce que le FXML ?
- Comment tester si le FXML est supporté sur ma plateforme ?
- Comment charger un fichier FXML ?
- Que signifie l'erreur « Location is not set. » en chargeant un fichier FXML ?
- Comment définir du texte internationalisé dans un fichier FXML ?
- Comment charger un fichier FXML contenant du texte internationalisé ?
- Que signifie l'erreur « No resources specified. » en chargeant un fichier FXML ?
- Comment inclure une ressource média ou une image dans un fichier FXML ?
- Comment inclure un fichier FXML dans un autre fichier FXML ?
- Comment inclure du scripting dans un FXML ?
- Comment référencer un objet du document FXML depuis le script ?
- Comment externaliser le script hors du document FXML ?
- Quels sont les langages de script supportés ?
- Comment injecter le nœud racine dans un document FXML ?
Le FXML est un format de fichier propre à JavaFX et servant, entre autres, à définir des interfaces graphiques. Ce format utilise tout simplement une syntaxe XML.
Prenons par exemple le fichier FXML suivant :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"/> |
Ici, les directives <?import?> servent à importer des packages Java présents sur le CLASSPATH, permettant de résoudre le nom court des classes. Comme en Java les directives d'importation sont optionnelles : il est possible de définir des objets en utilisant le nom long de la classe au lieu du nom court.
Ce code définit ensuite un unique gestionnaire de mise en page de type AnchorPane défini dans un élément XML du même nom. Les propriétés id, prefWidth et prefHeight de ce nœud graphique sont définies ici par les attributs idoines.
Les attributs xmlns et xmlns:fx ne peuvent exister que sur l’élément racine du document.
Bien que ce format de fichier soit avant tout destiné à définir des contrôles et écrans, vous pouvez en fait initialiser pratiquement n'importe quel type d'objet Java en FXML, même si cet objet n'a aucune vocation graphique. Il faudra cependant veiller à ce que votre classe soit publique et dispose d'un constructeur par défaut ou d'un constructeur sans paramètre qui est public et qu'elle soit accessible sur le CLASSPATH lors du chargement du fichier FXML.
Pour tester si le FXML est supporté par votre plateforme, vous pouvez invoquer la méthode isSupported() de la classe javafx.application.Platform en lui passant en paramètre la valeur javafx.application.ConditionalFeature.FXML :
Code Java : | Sélectionner tout |
Platform.isSupported(ConditionalFeature.FXML);
Note : le support de FXML peut être disponible dans les runtimes JavaFX, mais non fonctionnel. Cela est par exemple le cas lorsque la JVM ne dispose pas d'un parser XML sur la plateforme. Dans ce cas, ce test retournera false.
Pour charger un fichier FXML, vous devez utiliser un chargeur, un objet de type javafx.fxml.FXMLLoader. Vous devez initialiser cet objet avec l'URL d’accès à votre fichier FXML et ensuite invoquer sa méthode load() pour charger le fichier. Si elle s’exécute correctement, cette méthode retourne l'objet défini en nœud racine dans le fichier FXML.
Il est possible de récupérer un fichier FXML à charger de trois manières :
- le fichier FXML peut être empaqueté dans une bibliothèque ou une application et récupéré via le mécanisme des ressources ou des ClassLoader.
Par exemple :Code Java : Sélectionner tout 1
2
3final URL fxmlURL = getClass().getResource("monFXML.fxml"); final FXMLLoader fxmlLoader = new FXMLLoader(fxmlURL); final Node node = fxmlLoader.load();
Ici, nous chargeons notre fichier FXML depuis les ressources du projet inclus dans le fichier JAR de l'application ou de ses dépendances ; - le fichier FXML peut être situé sur un disque local et peut être référencé par les classes File, Path, URI ou URL.
Par exemple :Code Java : Sélectionner tout 1
2FXMLLoader fxmlLoader = new FXMLLoader(new File("monFXML.fxml").toURI().toURL()); final Node node = fxmlLoader.load();
- le fichier FXML peut être hébergé sur un site web distant et on peut y accéder par une String ou une URL contenant son chemin d’accès.
Par exemple :Code Java : Sélectionner tout 1
2FXMLLoader fxmlLoader = new FXMLLoader(new URL("http://monsite/monFXML.fxml")); final Node node = fxmlLoader.load();
Note : il n'est pas recommandé d'utiliser les variantes statiques de la méthode load() de la classe FXMLLoader. Préférez l'utilisation des méthodes d'instance.
Cette erreur indique que le FXMLLoader ne trouve pas votre fichier FXML. Vérifiez que le chemin donné est correct ou que l'objet de type URL retourné par le mécanisme d’accès aux ressources n'a pas une valeur égale à null (auquel cas, le fichier FXML n'est pas présent dans votre fichier JAR ou votre chemin d’accès n'est pas valide).
Pour définir des chaines de texte internationalisées (I18N, L10N) dans un fichier FXML, vous devez préfixer le texte par le caractère %. Lors du chargement du fichier, le chargeur tentera alors de substituer le texte internationalisé.
Par exemple :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"> <children> <Label text="%hello.message"/> </children> </AnchorPane> |
Au chargement de ce fichier FXML, le chargeur tentera de substituer la valeur « hello.message » par une chaine de texte provenant d'un fichier de traduction utilisant le mécanisme habituel des ResourceBundle.
Par exemple un fichier de traduction FR contiendra :
Code : | Sélectionner tout |
hello.message=Salut le monde !
Code : | Sélectionner tout |
hello.message=Hello World!
Pour charger un fichier FXML contenant des chaines de texte internationalisées (I18N, L10N), vous devez initialiser votre FXMLLoader en lui passant en second paramètre un objet de type ResourceBundle.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 | final URL fxmlURL = getClass().getResource("monFXML.fxml"); final ResourceBundle bundle = ResourceBundle.getBundle("monpackage.monbundle"); final FXMLLoader fxmlLoader = new FXMLLoader(fxmlURL, bundle); final Node node = fxmlLoader.load(); |
Après chargement, les chaines de texte internationalisées contenues dans le FXML seront substituées par le texte traduit provenant de vos fichiers de traduction en fonction de la Locale actuelle de la JVM.
Une exception sera levée si le chargeur ne trouve pas la clé correspondant à une chaine de texte internationalisée dans le ResourceBundle fourni.
Cette erreur indique que votre FXML contient des chaines de texte internationalisées (I18N, L10N), mais que vous n'avez pas fourni à votre FXMLLoader un ResourceBundle qui permettrait de les résoudre au chargement du fichier.
Pour inclure une ressource média ou une image (c'est-à-dire que le média ou l'image est empaqueté en tant que ressource de l'application) dans un fichier FXML, il faut préfixer le chemin relatif donné en valeur de la propriété url avec le caractère @.
Par exemple :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.image.*?> <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"> <children> <ImageView fitHeight="150.0" fitWidth="200.0"> <image> <Image url="@image.png" /> </image> </ImageView> </children> </AnchorPane> |
Ici, le fichier image.png est chargé en tant que ressource de l'application.
Note : il est également possible d'utiliser le caractère @ pour préfixer une URI sur un fichier sur le disque local ou une URL distante, mais cela n'a aucun effet particulier.
Pour inclure un fichier FXML dans un autre fichier FXML, il faut déclarer un élément de type <fx:include>. Cet élément référence le chemin d’accès vers le fichier inclus dans son attribut source.
Prenons ce simple fichier FXML qui sera le fichier secondaire, test.fxml :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"/> |
Et incluons-le dans un autre FXML, le fichier principal, master.fxml :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"> <children> <fx:include source="test.fxml"/> </children> </AnchorPane> |
Au chargement du fichier principal, le contenu du fichier secondaire sera lui aussi chargé et intégré dans l'arborescence du contenu du fichier principal. Il est possible d'utiliser sur cet élément les mêmes attributs de positionnement, etc. que sur les éléments déclarant d'autres nœuds graphiques.
Une exception sera levée au chargement si le fichier secondaire n'est pas accessible ou corrompu.
Il est possible d'utiliser des langages de script pour écrire des actions à effectuer, par exemple en cas de clic sur des boutons, directement dans le fichier FXML.
Par exemple :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?language javascript?> <StackPane id="StackPane" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"> <fx:script> function sayHello() { print("Salut le monde !"); } </fx:script> <children> <Button text="Dire "Salut"" onAction="sayHello()"/> </children> </StackPane> |
La directive <?language?> indique que nous allons utiliser ici l’interpréteur JavaScript qui est fourni avec le JRE.
L’élément <fx:script> qui est inclus dans l’élément racine de notre document nous permet de définir du code JavaScript, ici une fonction sayHello() qui affiche "Salut le monde !" sur la console.
Dans l’élément <Button>, nous affectons le nom de la fonction sayHello() dans la propriété onAction du bouton.
Chargeons ce fichier FXML dans une IU :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | final URL fxmlURL = getClass().getResource("fxmljavascript.fxml"); final FXMLLoader fxmlLoader = new FXMLLoader(fxmlURL); final Node node = fxmlLoader.load(); final StackPane root = new StackPane(node); final Scene scene = new Scene(root, 300, 250); primaryStage.setTitle("Test sur FXML et JavaScript"); primaryStage.setScene(scene); primaryStage.show(); |
Désormais, quand nous cliquons sur le bouton, la chaine de texte « Salut le monde ! » s'affiche dans la console. Notre code JavaScript est bien exécuté !
Note : le script étant stocké à même le fichier FXML, vous serez sans doute amené à devoir échapper des caractères spéciaux du format XML.
Il est possible de référencer et de manipuler des objets qui sont définis dans le FXML directement depuis le code du script inclus dans ce même fichier. Pour ce faire, il faut utiliser l'attribut fx:id pour donner un nom unique à chaque élément du document. On peut alors utiliser ce nom en tant que variable dans le code du script pour invoquer des méthodes sur les objets référencés.
Par exemple :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?language javascript?> <StackPane id="StackPane" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"> <fx:script> function sayHello() { print("Salut le monde !"); helloButton.setStyle("-fx-base: red;"); } </fx:script> <children> <Button fx:id="helloButton" text="Dire "Salut"" onAction="sayHello()"/> </children> </StackPane> |
Ici, notre bouton peut désormais être référencé dans le script en utilisant la variable helloBouton. Quand nous cliquons sur le bouton, nous changeons son style pour lui donner une couleur rouge.
Il est possible d'externaliser le script hors du fichier FXML ce qui permet de découpler plus aisément la partie vue (le FXML) et son contrôleur (le script). Lorsque le code a été déplacé dans un fichier externe, il suffit de déclarer le chemin d’accès vers le script dans l'attribut source de l’élément <fx:script>. Ce chemin peut être une URL vers un site distant, une URI sur un fichier local ou un chemin relatif dans les ressources de l'application.
Par exemple, nous avons déplacé le code vers un fichier script.js :
Code JavaScript : | Sélectionner tout |
1 2 3 4 | function sayHello() { print("Salut le monde !"); helloButton.setStyle("-fx-base: red;"); } |
Ce qui nous permet de modifier notre fichier FXML comme suit :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?language javascript?> <StackPane id="StackPane" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"> <fx:script source="script.js"/> <children> <Button fx:id="helloButton" text="Dire "Salut"" onAction="sayHello()"/> </children> </StackPane> |
Nous pouvons toujours accéder aux variables déclarées par les attributs fx:id dans le document FXML.
Note : le script étant stocké dans un fichier externe, il n'y a plus besoin d’échapper les caractères spéciaux du format XML.
A priori, n'importe quel langage de script qui fonctionne sur la JVM (Groovy, Scala, Ruby, Python, R, etc.), même s'il requiert l'utilisation de bibliothèques tierces, peut être utilisé. Il faudra cependant veiller à ce que moteur de script soit correctement implémenté en suivant les directives de la JSR223 et que les fichiers JAR nécessaires à l'initialisation et au fonctionnement du moteur de script soient sur le CLASSPATH lors du chargement du fichier FXML.
Cependant, en pratique, le degré d’implémentation de la JSR et de maturité de l’interpréteur fait que le support de tel ou tel langage puisse être partiel ou carrément non fonctionnel.
De manière générale, le support de l'utilisation du langage JavaScript dans du FXML est pleinement fonctionnel dans les JDK7 (rhino) et JDK8 (nashorn).
Il est possible d'injecter le nœud racine d'un document FXML. Pour cela, nous allons écrire le fichier FXML en utilisant l’élément <fx:root>, puis nous allons injecter un nœud du même type en invoquant la méthode setRoot() du FXMLLoader avant d'invoquer sa méthode load().
Prenons le fichier FXML suivant :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <fx:root type="javafx.scene.layout.VBox" id="root" spacing="10" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <Button fx:id="button1" text="Button1"/> <Button fx:id="button2" text="Button2"/> <Button fx:id="button3" text="Button3"/> <Button fx:id="button4" text="Button4"/> <Button fx:id="button5" text="Button5"/> </fx:root> |
Ici, le nœud racine du document a été décrit en utilisant un élément <fx:root>. Nous avons défini un attribut type qui indique que le nœud racine est en fait une VBox. Il est impossible de charger directement le fichier FXML, cela lèverait une exception.
Nous pouvons cependant injecter un nœud racine du type approprié avant de charger le fichier :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 | final URL fxmlURL = getClass().getResource("testroot.fxml"); final FXMLLoader fxmlLoader = new FXMLLoader(fxmlURL); final VBox newRoot = new VBox(); fxmlLoader.setRoot(newRoot); final Node node = fxmlLoader.load(); System.out.println(newRoot == node); |
Ici nous avons injecté un nœud racine dans le document FXML. De plus, nous pouvons voir que le nœud retourné par la méthode load() est en fait la racine que nous avons injectée dans le document.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.