Ch. 1 — JavaFX : widgets et placement
Ce qu'est un système interactif, la plateforme JavaFX (Stage, Scene, graphe de scène), les familles de widgets et les gestionnaires de placement — avec les quatre tailles d'un nœud et le redimensionnement.
Un système interactif
« Un système interactif est un système qui prend en compte, pendant son exécution, des informations communiquées par un ou plusieurs utilisateurs, et qui fournit, pendant son exécution, une représentation perceptible de son état interne. »
Ce n'est donc pas un système algorithmique : son fonctionnement dépend d'informations externes qu'il ne contrôle pas. Le paradoxe de l'IHM : beaucoup de systèmes semblent « tomber en marche », alors que la conception de l'interface peut absorber jusqu'à 80 % du temps de développement et conditionne le succès ou l'échec du produit. L'interface idéale ne demanderait aucun apprentissage, permettrait de réaliser toutes ses tâches rapidement et sans erreur avec peu d'effort, et satisferait ses utilisateurs. Comme cet idéal n'existe pas, tout est affaire de compromis pouvoir d'expression / simplicité, résumé par la devise d'A. Kay : « simple things should be simple, complex things should be possible ».
De AWT à JavaFX
Trois générations de bibliothèques graphiques se succèdent :
- AWT (Abstract Window Toolkit) : les composants utilisent des ressources propres au système — l'apparence diffère d'une plateforme à l'autre et les fonctionnalités restent rudimentaires ;
- Swing : offre beaucoup plus de composants, affichés de façon identique quel que soit le
système (le Look-and-feel configure la représentation visuelle) ; ses classes commencent
par la lettre
J; - JavaFX : le successeur de Swing, inclus dans Java 8 en 2014, puis module séparé à partir de Java 11 (2018).
Stage, Scene et point d'entrée
Le point d'entrée d'une application JavaFX est une classe qui hérite de Application. La
méthode launch effectue les travaux préparatoires, puis appelle start en lui transmettant
la fenêtre — le Stage — créée par l'application :
public class HelloJavaFX extends Application {
@Override public void start(Stage stage) {
stage.setTitle("Hello JavaFX Application");
stage.show(); // toujours à la fin de start
}
public static void main(String[] args) {
Application.launch(args);
}
}Le Stage contient une Scene, qui contient les widgets de la fenêtre :
Button bouton = new Button("Bouton");
Scene scene = new Scene(bouton, 300, 50);
stage.setScene(scene);Le widget et ses tâches élémentaires
Un widget est un objet graphique interactif — on parle de control en JavaFX. Bouton, potentiomètre, case à cocher, champ texte et boîtes de fichiers existaient dès le Macintosh de 1984 ; menus hiérarchiques, listes, combo box et onglets sont venus ensuite. Les tâches élémentaires d'interaction se classent en familles :
- Saisie : de texte (
TextField,TextArea), de quantités (Slider,Spinner), de positions (pointage), de tracés ; - Sélection d'un ou plusieurs éléments dans un ensemble : cardinal fixe (menu, boutons
radio, cases à cocher) ou variable (liste,
ComboBox, pointage) ; menus déroulants, pop-up ou palettes, organisés hiérarchiquement ou circulairement ; leRangeSlidersélectionne une plage de valeurs — de 13 à 24 secondes pour trouver un film dans une liste de 10 000 ; - Déclenchement : boutons et menus, clic-tirer (le drag-and-drop, où l'action dépend de la source et de la destination), entrée gestuelle ;
- Défilement (
ScrollPane) et spécification d'arguments et de propriétés : boîtes de dialogue modales ou non, boîtes à onglets, boîtes de propriétés à effet immédiat.
Fenêtre modale
Une fenêtre B est modale par rapport à une fenêtre A si l'affichage de B empêche
l'accès — et non la vue — à la fenêtre A. En JavaFX : stage2.initOwner(stage) puis
stage2.initModality(Modality.WINDOW_MODAL).
Le graphe de scène
Le graphe de scène structure la représentation spatiale de l'interface sous forme
d'arbre : chaque nœud a plusieurs enfants mais un seul parent ; il possède une racine —
celle qu'on passe à la Scene ; ses feuilles sont des widgets, ses nœuds internes des
conteneurs, qui peuvent contenir widgets et conteneurs. Dans un conteneur, les enfants sont
stockés dans une ObservableList<Node>, accessible par getChildren(), qui propose add
et addAll — le varargs Java, un seul paramètre variable par méthode, toujours en dernier.
Les quatre tailles d'un nœud
Chaque nœud possède quatre tailles : la taille idéale (preferred size), la taille
minimale, la taille maximale et la taille réelle. Un layout essaie de rendre la taille réelle
la plus proche possible de la taille préférée, compte tenu de sa stratégie et de la taille du
conteneur. Un widget ne grandit jamais au-delà de son maximum : pour étirer un bouton sur
toute la place offerte, on écrit top.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE).
Les gestionnaires de placement
Un conteneur possède un gestionnaire de placement (layout manager) qui calcule la position et les dimensions de chacun de ses enfants suivant une stratégie donnée. La question à se poser en permanence : que se passe-t-il quand on agrandit la fenêtre ?
Pane: positionnement absolu —bouton1.relocate(30, 20)— origine au coin supérieur gauche ;BorderPane: cinq zonestop,left,right,bottom,center(viasetTop…) ; il satisfait la plupart des applications de bureau ;FlowPane: les nœuds les uns à côté des autres ou les uns en dessous des autres, la ligne étant coupée quand elle est pleine ;HBoxetVBox: une ligne, une colonne :
HBox hb = new HBox();
hb.setSpacing(3); // espace entre les widgets
hb.setAlignment(Pos.CENTER_LEFT); // alignement des widgets
hb.setPadding(new Insets(3, 3, 3, 3)); // espace autour de la HBox
hb.getChildren().addAll(lbl_nom, tf_nom, bt_ok, bt_cancel);
HBox.setHgrow(tf_nom, Priority.ALWAYS); // méthode statiquesetHgrow contrôle la priorité d'agrandissement d'un nœud quand la fenêtre s'élargit —
croissance bornée par la taille maximale. Pour coller un bouton au bord droit, on insère
une Region vide comme espaceur et on lui donne le Hgrow : c'est elle qui absorbe
l'excédent.
TilePane: disposition en grille dont toutes les cellules ont la même taille ;GridPane: un nœud peut occuper plusieurs cellules —gp.add(b, 1, 1, 1, 2)place le bouton en 2e colonne, 2e ligne, sur 1 colonne et 2 lignes — avecsetHgap/setVgapetsetGridLinesVisible(true)pour visualiser la grille ;ToolBar,TabPane(onglets viagetTabs().addAll(...)) etSplitPane(séparateur,setDividerPositions(0.3)) n'héritent pas dePane; dans unSplitPane, chaque item doit être un gestionnaire de placement pour que le séparateur soit manipulable.
Avant de coder, dessinez le graphe
Pour reproduire une interface — et la faire tenir au redimensionnement — dessinez d'abord son graphe de scène : widgets, conteneurs, gestionnaires, et qui grandit. Le cours mentionne enfin JavaFX Scene Builder, un générateur d'interfaces.
A retenir
- une interface = un graphe de scène : widgets en feuilles, conteneurs en nœuds internes,
racine posée dans la
Scene, fenêtre =Stage; - chaque conteneur applique une stratégie de placement : BorderPane, HBox/VBox, FlowPane, TilePane, GridPane, ToolBar, TabPane, SplitPane ;
- chaque nœud a quatre tailles ; le layout rapproche la taille réelle de la taille préférée, jamais au-delà du maximum ;
- le comportement au redimensionnement se décide dans le graphe :
setHgrow,Regionespaceur,setMaxSize.
R2.02 - Cours 1 - Introduction - widgets (partie 1).pdf
R2.02 · Cours 1 — Introduction et widgets (1/2) · 31 diapositives
Chargement du document…
R2.02 - Cours 1 - Introduction - gestionnaires de placement (partie 2).pdf
R2.02 · Cours 1 — Gestionnaires de placement (2/2) · 37 diapositives
Chargement du document…
Dernière mise à jour le