Vous êtes sur la page 1sur 35

Ateliers logiciel : TD01

OO : Concepts de base : classes et objets, encapsulation, invariants et immutabilité

CLASSES:
1) Il affiche d’abord “(0,0)” et après la méthode move, il affiche “(2,2)”.
2) L’erreur que l’on reçoit est la suivante : la classe ne se trouve pas dans un
fichier correspondant à son nom, elle devrait se trouver dans un fichier
“TestPoint.java”
3) Il ne se passe rien : sans modificateur, elle peut être utilisée uniquement à
l’intérieur du package.

MEMBRES:
1) On ne peut pas avoir accès à l’attribut x car il a comme visibilité “private”. “x
has private access in esi.atl.oo_base.Point”
2) Le programme affiche d’abord la méthode move(int,int) car lorsqu’on a utilisé
la méthode move, on a placé des int en paramètre. Cependant, lors de
l’affichage du point, la méthode toString fait directement référence aux
composantes qui sont de type double, d’où l’apparition des points. Il reste
cependant possible d'additionner des double et des int, la conversion étant
réalisée automatiquement.
3) Le compilateur ne voudra pas compiler la nouvelle méthode : il existe déjà
une méthode s’appelant “move” avec les même paramètres. La différence au
niveau du type de retour importe peu.
CONSTRUCTEUR:

1) “Call to this must be first statement in constructor” : en commençant par une


autre instruction que le constructeur, l’erreur apparaît.

2) Comme le constructeur sans paramètre n’existe plus, l’initialisation du point p


ne peut plus se faire (elle se faisait initialement sans paramètres).

Non, il n’y plus d’erreurs mais le compilateur attribue directement des valeurs
par défauts aux attributs (constructeur par défaut). Comme les attributs sont
des primitives double, il attribuera la valeur 0 pour les deux attributs.

Le programme affiche donc (0.0,0.0) puis (2.0,2.0).

3) Il affiche les instructions précédentes mais toutes augmentée de 10. Le


programme se lance normalement.
ENUMERATION :

ENCAPSULATION :

1)

2)
COPIE DÉFENSIVE:

1) . Bien qu’on ai créé un nouvel objet cercle à


partir de p, la modification de ce dernier entraîne également une modification
de la valeur au sein de l’objet cercle. Plutôt que de copier les valeurs, nous
avons collé la référence de l’objet point.

2)

3) En ayant créé un objet non plus à partir de l’objet directement (à comprendre


sa référence) mais à partir des valeurs de ses attributs, un nouvel objet
indépendant est créé.

Quand le nouveau point p2 est créé, ce dernier l’est via la méthode getCenter
sur c, qui copie la référence du point au centre : quand nous modifions p2,
nous modifions en réalité l’objet référencé, c’est à dire le centre de l’objet c.

4) Cette fois-ci, la méthode getCenter du cercle renvoie bien un nouvel objet


indépendant : en modifiant ce nouveau point, le centre du cercle n’est plus
modifié (le point p2 ne contient pas la référence au centre du cercle).
5) . Les éléments sont tous
indépendants, certaines valeurs sont certes égales mais la modification d’une
des valeurs n'entraîne plus la modification des attributs des autres objets.

Constructeur par copie


Préserver les invariants de la classe

1) .

2)
3) L’invariant n’est plus respecté, le périmètre négatif en conteste (il est
négatif) : en ayant modifié directement le point bl, qu’on référence directement
dans le rectangle, on utilise la méthode move du point et pas celui du
rectangle. Ainsi, la vérification n’est pas exécutée et on a “indirectement”
modifié le rectangle.
4)

. Comme la classe Point a été modifié précédemment et qu’un constructeur


de “copie” a été ajouté, il suffit de créer ce nouveau rectangle à partir de copie
indépendante des points spécifiés dans le constructeur. En modifiant le point
d’origine, le rectangle n’est plus modifié.
Objets immuables
TD02 : Héritage et Polymorphisme :

Héritage :

L’héritage est une technique qui permet à une classe, dite sous-classe ou classe
enfant de récupérer le type, les attributs et les méthodes d’une classe, dite super-
classe ou classe parent.

Questions :

1) Le programme affiche d’abord les coordonnées du point p dans la couleur


mise en paramètres. Ensuite il affiche les coordonnées de x et enfin il affiche
la couleur.
2) Dans la ligne où se trouve l'instruction suivante :
System.out.println("color : " + String.format("%08X", p.getColor())); , le
compilateur nous dira qu’il ne trouve pas la méthode getColor(). Si nous la
mettons en commentaire, nous n’aurons plus de soucis. Nous avons une
erreur de compilation car nous avons initialisé un objet Point. Dans la classe
point, nous n’avons aucun attribut représentant une couleur. Il existe une
classe ColoredPoint qui hérite de la classe Point pour pouvoir permettre
d’attribuer des couleurs. La méthode getColor se trouve dans la classe
ColoredPoint et non pas Point.
3) Non parce qu’on ne peut pas convertir la variable p2 qui est instancié en
ColoredPoint en Point
4) Non parce que les attributs x et y sont des attributs privé càd qu’on ne peut
pas les prendre en dehors de la classe objet où ils ont été créés.
5) ça créé une sorte de cycle d’erreur car : La classe ColoredPoint est une sous
classe de Point. Si nous disons que la classe Point est une sous classe de
ColoredPoint, où se trouve la classe parent ? Il faut forcément avoir une
classe parent sinon ça ne fonctionnera pas.
6) Si on rajoute le mot clé final pour initialiser une classe, une autre classe ne
pourra pas hériter de celle-ci. Le compilateur ne va pas être content et va
lâcher une erreur.

Résumé :
Classe Object :
Questions :

1) Oui on peut car toute classe objet créée hérite forcément de la classe Object
de la bibliothèque java.lang
2) Oui car la classe ColoredPoint hérite la classe Point qui hérité elle même de
la classe Object. Et puis toute classe objet hérite de la classe Object.
3) Oui on peut ajouter cette instruction dans le main. Cette méthode est définie
dans la classe Object. On peut l’appeler sur un objet ColoredPoint pour les
mêmes raisons expliqué dans la question 2

Théorie :

La classe Point ne déclare pas de super-classe (pas de mot-clef extends dans sa


déclaration). Elle étend par défaut la classe Object. Sa déclaration est équivalente
à:
public class Point extends Object
La classe Point hérite donc du type, des méthodes et des attributs de la classe
Object. La classe ColoredPoint hérite également, au travers de la classe Point, de
tous les éléments de la classe Object.
La javadoc de la classe Object indique :
Class Object is the root of the class hierarchy. Every class has Object as a
superclass. All objects, including arrays, implement the methods of this class.

Constructeur :

Questions :

1) le mot clé super lorsqu’un créé un constructeur d’une classe extends doit
toujours être le première instruction. C’est pour cela que nous avons une
erreur.
2) Le constructeur d’une classé hériter doit se souvenir des attributs hérités. Si il n’y a
pas de super, le compilateur ne pourra pas savoir où se trouve les attributs → ici c’est
double x et double y. super sert à aller chercher les attributs d’une classe hérité.
3) On a une erreur mais pas la même. (je ne comprend pas trop l’erreur donc je
passe)

1) il affiche : constructor of A, constructor of B, constructor of C.


2) il affiche : constructor of A, constructor of B
3) Après l’ajout des super, l’effet est le même que pour la questions 1.
4) ???

Théorie :

Constructeur et héritage :
Exécution des constructeur :

Redéfinition de méthodes :

Questions :

1) il affiche : (0.0, 0.0) - not pinned et (1.0, 1.0) - pinned


2) la méthode move utilisé ici pour p est la méthode move de la classe
PinnablePoint car l’objet référencé par la variable à ce moment-là est de type
PinnablePoint
3) On ne peut pas faire en sorte que les méthodes Override puissent throw des
exceptions sachant que la méthode de base ne le fait pas.
4) Non on n’a plus d'erreur et je ne sais pas pourquoi
5) oui
6) non
7) oui parce que Object n’est pas compatible avec Point.
8) Comme la méthode de Point était public, la méthode de PinnablePoint ne
peut pas Override car il est en protected donc ne peut voir la méthode de
Point
9) L’appel méthode move sert à appeler la méthode de la classe Point pour ne
pas réécrire les instructions de cette méthode dans une nouvelle classe.

Théorie :

Polymorphisme :

Le polymorphisme en Java désigne la possibilité qu’une variable d’un type déclaré


référence (à des moments différents de l’exécution) des objets de types différents.
De plus, un même appel de méthode sur une telle variable ne déclenche pas
toujours l’exécution du même code. Cela dépendra du type de l’objet référencé.

- Qu’affiche le programme TestPolymorphism


Il affiche tout d’abord le toString de la classe Point (“(1.0,1.0)”), ensuite le
toString de ColoredPoint (“(3.0, 5.0) - FF0000FF”) et enfin le toString de
PinnablePoint (“(2.0, 2.0) - not pinned”).

Dans cet exemple, la méthode printPoints reçoit une liste de Point. La boucle
assigne un à un les points de la liste à la variable p qui est de type Point.
Pour générer l’affichage, un appel (polymorphique) est fait aux méthodes move et
toString. Le code des méthodes move et toString réellement exécuté dépendra du
type de l’objet référencé. Il se trouvera dans la classe point, ou dans la classe
ColoredPoint ou encore dans la classe PinnablePoint selon le type de l’objet
référencé à ce moment-là
L’héritage et la rédéfinition sont des éléments essentiels de l’implémentation du
polymorphisme en Java.

Interface :

Les interfaces en java permettent de définir des contrats que les classes doivent
respecter. Ce contrat a la forme d’une liste de méthodes.

Questions :

1) On constate que placer le mot clé “protected” n’est pas permis pour les
méthodes dans une interface.
2) On constate qu’on peut placer le mot clé public devant les méthodes dans
une interface.
3) (à faire sur netbeans, là tu es juste sur un traitement de textes)
4) Il affiche tout d’abord le toString de la classe Point (“(1.0,1.0)”), ensuite le
toString de ColoredPoint (“(3.0, 5.0) - FF0000FF”) et enfin le toString de
PinnablePoint (“(2.0, 2.0) - not pinned”).
L’intérêt des interfaces est de les utiliser comme type de
variable/attribut/paramètre/retour (ex : l’interface List). Alliées au polymorphisme,
elles donnent plus de souplesse aux implémentations.
Classe abstraite :
Une classe doit être déclarée abstraite si toutes ses méthodes ne sont pas
implémentées. Notez également que, même si toutes les méthodes d’une classe
sont implémentées, une classe peut être déclarée abstraite. Suite dans la
documentation.

Polymorphisme :

Type déclaré et type effectif :

Question 1 :

1) L’instruction va renvoyer la méthode bar() de la classe A → 3


2) L’instruction va renvoyer la méthode bar() de la classe A → 3
3) L’instruction va renvoyer la méthode foo() de la classe B + 5. la méthode foo() qui
retourne la méthode bar() de la classe A → 9
4) idem que pour 3. → 9
5) idem que pour 3. → 9
6) idem que 2. → 3

Question 2 :

1) B a2 = new A() ne compilera pas car un type B ne peut être converti en type
A.
2) toutes les instructions commençant par a2 ne compileront pas
3) a1.c et b1.c ne compileront pas car c’est une méthode qui provient de la
classe B.
4) ((B) a1).c() ne compilera pas car on ne peut pas convertir un type a à un type
B.
a de A
a de A
a de A
b de A
b de B
c de B
c de B
c de B

Théorie :
Mécanisme de sélection de méthode :
Lors de la définition d’une sous-classe, une méthode peut être héritée, redéfinie ou
surchargée. Le compilateur et, à l’exécution, la machine virtuelle jouent chacun un
rôle précis pour choisir la méthode qui sera exécutée. Cette section présente ce
mécanisme de sélection de méthode.

Questions :

1) L’instruction va afficher : Square:add(Figure)


2) L’instruction va afficher : Square:add(Figure)
3) l’instruction va afficher : Rectangle:add(Rectangle)
4) L’instruction va afficher : Rectangle:add(Rectangle)

Théorie :

Par exemple : considérons l’appel rs.add(fs);


- Le type déclaré de rs est Rectangle alors que son type réel (le type de l’objet
référencé lors de l’appel) est Square
- Le type déclaré du paramètre fs est Figure (son type réel est Square mais
cela ne joue pas dans la sélection de la méthode)
- Le compilateur choisit l’en-tête le plus proche correspondant à add(Figure)
(car Figure est le type déclaré du paramètre) dans la classe Rectangle (type
déclaré de rs). Cette classe possède une méthode avec cet en-tête exact.
L’en-tête sélectionné par le compilateur est donc add(Figure).
- A l’exécution, la machine virtuelle considère le type réel de rs (c’est un
Square), et appelle la méthode add(Figure) sélectionnée par le compilateur.
Cette méthode est redéfinie dans la classe Square, le message est donc :
Square:add(Figure)
ATELIER LOGICIEL : TD3
JavaFX

Hello, world !

Pour déclarer du texte, on utilisera :

Text helloText=new Text("Hello World");

Pour changer la police du texte :

helloText.setFont(Font.font("Times New Roman", 30));

Pour changer la couleur du texte :

helloText.setFill(Color.RED);

La salle de spectacle
La description d'une application JavaFX suit l'analogie de la salle de spectacle :

● Stage : endroit où se déroule le spectacle


import javafx.stage.Stage

● Scene : endroit où se déroule l'action


import javafx.scene.Scene

● Layout : organisation de l'interface graphique au sein d'une Scene


import javafx.scene.layout.BorderPane
Dans l'exemple ci-dessus, le layout utilisé est le BorderPane, qui divise l'écran en 5
zones : Top, Bottom, Left, Right et Center.

Au sein de ces différentes zones, on retrouve les composants de l'interface


graphique. Il s'agit de libellés, de boutons ou encore de cases à cocher, qui
constituent les éléments actifs de l'application. On parle de Controls. Chaque
composant aura droit à une importation spécifique, dans notre exemple il s'agit de
l'import suivant :

import javafx.scene.text.Text

Questions
1) En modifiant les paramètres numériques du code d'instanciation de scène suivant

Scene scene = new Scene(root, 250, 100);

… nous remarquons que la première valeur correspond au layout utilisé, la seconde


à la largeur de la fenêtre et la dernière à la hauteur de la fenêtre.

2) En modifiant la ligne de commande suivante …

primaryStage.setTile"XXX";

… le titre de l'application affiché dans la bordure de fenêtre change. De plus, en


rajoutant la ligne suivante…

primaryStage.initStyle(StageStyle.TRANSPARENT);

… le style de la bordure de fenêtre change. En terme de valeurs, voici la liste des


styles possibles :
Le style par défaut sera le premier, avec l'ensemble des options (agrandir la fenêtre,
la fermer, etc.).

3) Afin de placer le composant Text au centre de l'écran, nous avons fait appel à la
méthode setCenter() de la classe BorderPane :

BorderPane root = new BorderPane();

root.setCenter(helloText);

Cette zone correspond à celle évoquée précédemment. Il est ainsi tout à fait
possible d'utiliser les autres zones du layout :

● setTop() : le libellé est placé dans la zone supérieure du layout. Sans autres
précision, le libellé sera placé en haut à gauche.
● setBottom() : le libellé sera placé dans la zone inférieure du layout. Sans
autres précision, le libellé sera placé en bas à gauche.
● setLeft() : le libellé est placé dans la zone gauche du layout. Si la zone
supérieure est vide, cela donnera l'impression que le texte est en réalité dans
la zone supérieure. Si on venait à la remplir, alors le libellé viendrait se placer
juste en dessous de la zone supérieure, à gauche.
● setRight() : le libellé est placé dans la zone droite du layout. Si la zone
supérieure est vide, cela donnera l'impression que le texte est en réalité dans
la zone supérieure. Si on venait à la remplir, alors le libellé viendrait se placer
juste en dessous de la zone supérieure, à droite.
● setCenter() : le libellé est placé dans la zone centrale du layout et est
également aligné au centre.
Dans l'image à gauche, A remplit la zone supérieure. Dans celle de droite, la zone
supérieure est vide : les zones gauche et droite se placent accordement (il faut
imaginer la zone supérieure comme une crêpe très fine).

Les composants, controls et widgets


Une interface graphique passe par l'utilisation de boutons, de libellés, de zones de
texte, de cases à cocher et de différents objets appelés composants ou controls.

Ci-dessus, des exemples de boutons, de labels, de cases à cocher et de zones de


texte.

Labeled

De nombreux composants affichent et gèrent des textes (libellés, boutons, cases à


cocher, etc.). Afin de structurer au mieux le code, les différents composants gérant
du texte vont hériter de la classe Labeled :
Dans le cas d'un composant Labeled, trois propriétés sont intéressantes :

● Le texte affiché : text


● La police : font
● La couleur du texte : textFill
Label
Ce composant représente un texte non éditable, on parle de libellé. Il hérite de la
classe Labeled et de ses propriétés. Il existe plusieurs constructeurs pour cette
classe, dans l'exemple, nous utilisons celui qui prend en paramètre le texte à afficher
à l'écran.

De plus, il est possible d'accéder aux propriétés du label grâce à des getters, tel que
getText(), getFont() ou encore getTextFill().

Exercice

En se fiant à la documentation, on remarque qu'il est par exemple possible de


souligner le Label grâce à la méthode setUnderline(true).

CheckBox
Ce composant est typiquement utilisé lorsque l'utilisateur peut choisir parmi
plusieurs options qui peuvent être simultanément activée. Le composant
CheckBox représente une case à cocher qui est caractérisée par trois états :
désélectionné, sélectionné et indéterminé. Chaque clic de l'utilisateur fera passer le
composant d'un état à un autre.

Comme expliqué dans la documentation, cette classe dispose de deux


constructeurs.

new CheckBox();

new CheckBox("Faites votre choix") ;

Le premier constructeur instancie une CheckBox sans libellé.

Le second constructeur instancie une CheckBox avec libellé.


Les propriétés non héritées d'une CheckBox sont les suivantes :

● allowIndeterminate : si l'attribut prend la valeur false, la case passe


seulement par les états sélectionné ou désélectionné. Sinon, l'état
indéterminé sera ajouté.
● indeterminate : indique si l'état de la case est indéterminé.
● selected : indique si la case est sélectionnée.
Questions
Soit les cases à cocher suivantes :

Ainsi :

● La première checkBox est directement sélectionnée. Quand on clique dessus,


elle passe de l'état sélectionnée à désélectionnée et vice versa. L'état
indéterminé n'est pas disponible : il semble que allowIndeterminate est
initialisé sur faux par défaut.
● La seconde checkBox est d'abord indéterminée. Quand on clique dessus, elle
passe à l'état sélectionnée à désélectionnée et vice versa. L'état indéterminé
ne peut être atteint de nouveau, car allowIndeterminate est toujours sur faux.
On a simplement "forcé" la case au début.
● La troisième checkBox est d'abord désélectionnée. Elle oscille librement entre
les 3 états, car allowIndeterminate est vrai.
Si on supprime les lignes de code d'alignement…

BorderPane.setAlignment(checkBox1, Pos.CENTER);

BorderPane.setAlignment(checkBox3, Pos.CENTER);

… alors les cases 1 et 3 se placent de façon classique par rapport à la zone où elles
sont placées, c’est-à-dire gauche et droite. La méthode setAlignement() permet donc
d'aligner l'objet par rapport à la zone dans laquelle il se trouve (ici, centré
verticalement et horizontalement dans les zones gauche et droite).

TextInputControl

Terminé avec les labels, il est temps d'étudier les zones de texte. Comme on peut le
voir dans la figure suivante, la classe abstraite TextInputControl est la classe
parente de différents composants permettant à l'utilisateur de saisir du texte.

Il s'agit notamment des composants d'interface tels que TextField, PasswordField


et TextArea.

Cette classe définit les propriétés de base et les fonctionnalités communes aux
composants offrant une saisie de texte. Ces propriétés permettent la sélection et
l'édition de texte ou la gestion du curseur à l'intérieur du texte. On peut citer les
propriétés suivantes :

● Text : texte contenu dans le composant


● Editable : booléen rendant le texte éditable par l'utilisateur
● Font : police du texte
● Length : longueur du texte
Citons également les méthodes suivantes :

● clear() : efface le texte du composant


● insertText() : insère une chaîne de caractères dans le texte
● appendText() : ajoute une chaîne de caractères à la fin du texte
● selectAll() : sélectionne l'ensemble du texte
TextField
Le composant TextField représente un champ texte d'une seule ligne qui est
éditable par défaut. Il peut également être utilisé pour afficher du texte. Ce
composant hérite des propriétés de TextInputControl mais possède également les
propriétés suivantes :

● alignement : définit l'alignement du texte


● prefColumnCount : définit le nombre de colonnes pour le champ texte. La
valeur par défaut est de 12
● onAction : définit un évènement à générer lors d'une certaine action de
l'utilisateur, par défaut, lorsque l'utilisateur presse la touche enter
Questions
Soit la déclaration suivante :

Si on venait à remplacer le composant TextField en un PasswordField, les


caractères entrés sont remplacés par des • afin de ne pas divulguer le mot de passe.

Soit la déclaration suivante :


On définit un TextField classique, la particularité se situe au niveau de la méthode
setOnAction(). On définit directement comme paramètre un nouvel objet permettant
de gérer l'évènement. C'est l'instance d'une classe dont on réécrit la méthode
handle.

On indique qu'on place le label test dans la zone inférieure du layout, qu'on joue
avec les alignements, qu'on rend le champ de texte non éditable et que le nom entré
se trouve aligné au centre du champ.

TextArea
Le composant TextArea permet d'afficher et de saisir du texte dans un champ
multilignes (une zone de texte). Le texte peut être renvoyé à la ligne
automatiquement (wrapping) et des barres de défilement horizontales et/ou
verticales sont ajoutées automatiquement si la taille du composant ne permet pas
d'afficher l'entièreté du texte. Tous les caractères du texte possèdent les mêmes
attributs (police, style, taille, couleur, etc.).

Questions
Dans le code ci-dessous, nous avons ajouté l'utilisation d'un composant Button, qui
possède également la propriété onAction.
On a donc une zone de texte de 15 colonnes et 3 lignes, avec un retour à la ligne
automatique. Un bouton avec le libellé "Print" est également présent, avec comme
action quand il est pressé, d'afficher dans la console le texte inscrit dans la zone de
texte.

Les layouts
Jusqu'à présent, le positionnement des composants au sein d'un écran s'est fait en
utilisant les méthodes setCenter() ou setAlignement() d'un objet BorderPane. Celui-
ci fait partie de la famille des layouts. Ils permettent de définir la position au sein
d'une fenêtre des différents composants, les positions relatives de chaque
composant ainsi que les alignements et espacements de ceux-ci.

À moins d'être explicité, la disposition des composants est délégué à des


gestionnaires de disposition (layout managers) qui sont associés à ces
conteneurs/layouts.

Le graphe de scène

Le graphe de scène est une notion importante qui représente la structure


hiérarchique de l'interface graphique.
Il s'agit d'un arbre orienté constitué d'un nœud origine (root) et de nœuds enfants.
Tous les éléments contenus dans un graphe de scène sont des objets qui ont pour
classe parente la classe Node. Les layouts et les composants héritent tos de cette
classe. Cette représentation en terme d'arbre justifie l'utilisation de la méthode
node.getChildren() avant l'ajout d'un composant à un layout.

La documentation de la classe Pane nous indique que la méthode getChildren()


renvoie la liste des enfants du parent.

Les différents layouts

BorderPane
Le conteneur BorderPane est divisé en cinq zones pouvant chacune contenir un
seul objet Node. Il est à noter que :

● Les composants placés dans la zone Top et Bottom conservent leurs


hauteurs préférées (preftHeightProperty) et sont éventuellement agrandies ou
réduits horizontalement en fonction de la largeur du conteneur.
● De la même façon, les composants placés dans la zone Left et Right
conservent leurs largeurs préférées (prefWidthProperty) et sont
éventuellement agrandis ou réduits verticalement.
● Le composant placé dans la zone Center est éventuellement redimensionné
pour occuper l'espace restant au centre du conteneur.
● Si aucun composant n'est ajouté à une zone, celle-ci n'occupe plus aucun
espace.
Pour gérer la position d'un nœud au sein d'une zone, les méthodes suivantes sont
disponibles :

● alignement() : permet de modifier l'alignement par défaut du composant


passé en paramètre
● margin() : fixe une marge autour du composant passé en paramètre
HBox, Vbox
Le layout HBox place les composants sur une ligne horizontale de gauche à
droite à la suite les uns des autres. Il est possible d'utiliser la méthode getChildren()
pour ajouter des composants au layout.

Questions
Le layout Vbox place quant à lui, les composants sur une ligne verticale de haut en
bas :

Il est également possible d'utiliser la méthode addAll() pour la liste des enfants. Il
suffit de spécifier les éléments dans l'ordre souhaité :

root.getChildren().addAll(checkBox1, checkBox2, checkBox3);

Dans la documentation de Layout Vbox, on retrouve la remarque suivante :

VBox does not clip its content by default, so it is possible that childrens’ bounds may
extend outside its own bounds if a child’s min size prevents it from being fit within
the vbox

Il est possible qu'un enfant sorte des limites si sa taille minimale l'empêche de
rentrer complètement dans la Vbox, qui ne redimensionne pas les éléments par
défaut. Il faudra faire attention à ce qu'ils ne sortent pas de la boîte, en indiquant par
exemple une taille minimale de fenêtre. Il est également possible de rajouter des
contraintes pour chaque enfant.

GridPane
Le conteneur GridPane permet de disposer les différents composants au sein d'une
grille. Elle peut être irrégulière, les dimensions de ses cases ne sont pas
nécessairement uniformes. La zone occupée par un composant peut s'étendre
(span) sur plusieurs lignes et/ou colonnes. Lors de la construction d'un GridPane, il
est inutile de spécifier les nombres de lignes et de colonnes attendus : ceux-ci sont
déterminés par les endroits où sont placés les composants.

De même, la taille des cases de la grille est déterminée par la taille des
composants les plus imposants au sein d'une ligne ou d'une colonne. La méthode
add() d'un GridPane prend en paramètres la position de chaque composant :
La méthode add() existe selon deux versions :

● La première n'admet que le nœud, l'index de la colonne et l'index de la ligne.


● La seconde admet en plus de ça, le nombre de colonnes et le nombre de
ligne sur lequel s'étend le nœud.
Il est également possible de préciser l'alignement horizontal d'un nœud ou encore
les marges.

Questions
Si on place plusieurs composants dans une même cellule, ils se superposent
graphiquement.

En remplaçant le paramètre GridPane.setHalignment(lblPassword, HPos.CENTER) par


GridPane.setHalignment(lblPassword, HPos.RIGHT), le libellé du mot de passe est placé
à droite à l'intérieur de la case dans laquelle il se trouve.

En remplaçant les paramètres de GridPane.setFillWidth(tfdPassword, false) par


GridPane.setFillWidth(tfdPassword, true), on remarque que le champ mot de passe
prend toute la largeur disponible de sa case.

Imbrication de layouts : GridPane et HBox


Les alignements proposés par l'utilisation d'un unique layout ne suffisent pas
toujours à réaliser l'écran imaginé par le développeur. Il est très fréquent
d'imbriquer plusieurs conteneurs pour obtenir la disposition désirée des
composants de l'interface.

On remarque à la page suivante que l'on créé d'abord une grille via GridPane. On y
place nos éléments de départ mais on aimerait bien rajouter quelques boutons tout
en bas. On utilise donc le layout HBox qui sera parfait pour créer ce panneau de
boutons.

Quand HBox a été correctement configuré et rempli, on rajoute directement le


panneau dans la grille (c'est un nœud comme un autre après tout) et on utilise la
méthode setMargin() pour placer le tout comme il faut.

On a donc un nœud racine qui est ici la grille, dans laquelle on place plusieurs
nœuds, que ce soit de simples composants ou carrément des layouts, avec ses
propres enfants.
Autres layouts disponibles

Au-delà des layouts présentés dans ce document, il en existe tout un tas d'autres :

● FlowPane : place les composants sur une ligne horizontale ou verticale,


passe à la ligne ou à la colonne suivante lorsqu'il n'y a plus assez de place
disponible.
● StackPane : empile les composants enfants les uns au-dessus des autres
dans l'ordre d'insertion.
● TilePane : place les composants dans une grille alimentée soit
horizontalement, soit verticalement.
● AnchorPane : permet de positionner (ancrer) les composants enfants à une
certaine distance des côtés du conteneur.
● …

Vous aimerez peut-être aussi