
En Java, la création d'interfaces utilisateur (IUG) esthétiques et fonctionnelles implique souvent l'utilisation de bordures et une gestion précise de la mise en page des composants. L'objectif est de présenter les éléments de manière claire et organisée, tout en permettant une adaptation fluide aux différentes configurations et interactions de l'utilisateur.
L'Importance des Gestionnaires de Disposition (Layout Managers)
Lorsqu'on intègre un composant graphique dans un conteneur, il n'est pas nécessaire de préciser son emplacement car il est déterminé de façon automatique : la mise en forme est dynamique. On peut influencer cette mise en page en utilisant un gestionnaire de mise en page (Layout Manager) qui définit la position de chaque composant inséré. Il est possible d'utiliser plusieurs gestionnaires de mise en forme pour définir la présentation des composants.
Pourquoi les gestionnaires de disposition sont-ils indispensables ? Ils résolvent de nombreux problèmes, notamment les changements de taille provoqués par l'utilisateur ou la nécessité de traduire l'application dans d'autres langues. Certains mots prennent la même place dans différentes langues, ou à peu près de la même manière dans plusieurs langues. Cependant, de nombreux mots ont une longueur variable selon la langue utilisée. Par exemple, un simple bouton pour finir une application, lorsqu'il est traduit, peut voir le texte apparaître coupé. L'utilisateur ne voit alors pas la phrase entière.

Les gestionnaires de disposition calculent la position et la taille des composants d'une IUG. L'algorithme est gardé séparément, ce qui permet une flexibilité accrue. Cette fonctionnalité a été ajoutée à partir de la version 1.1 du JDK.
Comment les Gestionnaires de Disposition Fonctionnent
Chaque gestionnaire de disposition utilise des informations spécifiques pour décider du placement d'un composant. Les composants eux-mêmes décrivent la taille demandée via la méthode getPreferedSize(), qui indique la taille souhaitée mais pas celle imposée. Les conteneurs peuvent utiliser ou ignorer tout ou partie des souhaits que ces méthodes expriment. Pour ce faire, les composants peuvent surcharger les méthodes getPreferedSize(), getMinimumSize(), et getMaximumSize() pour expliciter l'information correspondante. Une autre approche consiste à les redéfinir, mais cela nécessite que le gestionnaire de disposition les prenne en compte.
Les gestionnaires de disposition sont associés à un conteneur via la méthode setLayout(LayoutManager) du conteneur. Après avoir défini le gestionnaire, on peut lui ajouter des composants. La méthode add() du conteneur passe les informations au gestionnaire de disposition correspondant.
Création de Bordures Visuelles
Un aspect crucial de la conception d'IUG est l'utilisation de bordures pour mettre en évidence ou séparer des éléments. Par exemple, l'objectif peut être d'afficher une bordure jaune autour de l'élément sélectionné dans une liste de contacts. Par défaut, au lancement de l'application, c'est le contact numéro 0 qui est sélectionné, et la bordure jaune apparaît sur cet élément. Ensuite, lors de la sélection d'un autre contact, la bordure jaune est mise à jour pour entourer le nouveau contact sélectionné.
Pour ce faire, un objet cadre de type BorderFactory est utilisé pour créer une ligne de bordure orange. L'affichage de cette bordure se fait via la méthode setBorder, en passant l'objet cadre en paramètre. Initialement, cette méthode est appliquée au contact numéro 0. Quand un utilisateur clique sur un autre contact, la méthode setBorder est à nouveau invoquée pour mettre à jour la bordure, mais il est nécessaire de mémoriser le numéro précédent pour retirer la bordure du contact désélectionné.
Il est également possible d'ajouter une bordure décorative autour d'un panneau, par exemple une bordure 3D surélevée entourant tout le panneau et réservant un espace comparable entre elle et les composants contenus. L'objet Insets (via la méthode getInsets()) renvoie un objet java.awt.Insets avec les champs top, bottom, left et right qui peuvent être utilisés pour son propre usage. Insets est un objet statique qui représente l'espace à réserver.
Les Différents Types de Gestionnaires de Disposition
Chaque gestionnaire de disposition a ses propres caractéristiques et est adapté à des scénarios de mise en page spécifiques.
1. FlowLayout : La Mise en Page Flot

La classe FlowLayout (mise en page flot) place les composants ligne par ligne de gauche à droite. Chaque ligne est complétée progressivement jusqu'à être remplie, puis passe à la suivante. Chaque ligne est centrée par défaut (mais peut être alignée à gauche ou à droite via des constantes comme CENTER, LEFT, RIGHT). FlowLayout utilise les dimensions de son conteneur comme seul principe de mise en forme des composants. Ce gestionnaire met autant de composants que possible sur une ligne donnée, et si l'espace le permet, tout le bazar est centré dans l'espace disponible.
On peut également jouer sur l'espace entre les composants. Pour ce faire, on va utiliser les propriétés setHgap(int hgap) et setVgap(int vgap) pour définir les écartements horizontaux et verticaux. Réfléchissez aux conséquences de cela. Qu'est-ce qui se passe si on place un conteneur géré par un FlowLayout dans un autre conteneur également géré par un FlowLayout ? Le résultat est déconcertant. Le gestionnaire FlowLayout est orienté horizontalement, ce qui signifie qu'un conteneur géré par un FlowLayout aura toujours une simple ligne si l'espace le permet.
La taille préférée d'un FlowLayout est la somme des tailles préférées de ses composants, si possible.
2. BorderLayout : La Mise en Page en Bordure

Avec ce Layout Manager, la disposition des composants est commandée par une mise en page en bordure qui découpe la surface en cinq zones : North, South, East, West, Center. BorderLayout consacre tout l'espace du conteneur aux composants.
Lors de l'ajout d'un composant, on précise la position que le composant doit occuper (par exemple, BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.EAST, BorderLayout.WEST, BorderLayout.CENTER). Les formes BEFORE_FIRST_LINE, AFTER_LAST_LINE, BEFORE_LINE_BEGINS, et AFTER_LINE_ENDS sont plus récentes et équivalent à NORTH, SOUTH, WEST, et EAST, respectivement, pour des écritures de gauche à droite et du haut vers le bas.
Le BorderLayout est un gestionnaire de disposition puissant mais avec quelques particularités. Si l'on ajoute un composant au Nord, sa taille préférée sera respectée. Les composants NORTH et SOUTH prennent toute la largeur disponible et occupent leur hauteur préférée. Les composants WEST et EAST prennent la hauteur restante et occupent leur largeur préférée. Le composant CENTER prend tout l'espace restant.
On peut spécifier des valeurs hgap et vgap au moment de la construction du BorderLayout. La taille préférée d'un BorderLayout est la somme des tailles préférées des composants placés sur les bords, plus les largeurs de ces lignes. Le BorderLayout est souvent utilisé pour la structure principale d'une IUG.
Java Swing GUI - How to use Border Layout
3. CardLayout : Les Boîtes de Dialogue à Onglets

Ce layout manager aide à construire des boîtes de dialogue composées de plusieurs onglets. Un onglet se compose généralement de plusieurs contrôles : on insère des panneaux dans la fenêtre utilisée par le CardLayout Manager. Chaque panneau correspond à un onglet de boîte de dialogue et contient plusieurs contrôles. Lors de l'insertion d'un onglet, un nom doit lui être attribué. Les fonctions nécessaires pour afficher un onglet de boîte de dialogue ne sont pas fournies par les méthodes du conteneur, mais seulement par le Layout Manager. Il est nécessaire de sauvegarder temporairement le Layout Manager dans une variable ou déterminer le gestionnaire en cours par un appel à getLayout().
Le CardLayout empile les composants les uns sur les autres, et un seul est visible à la fois. Les composants peuvent être ajoutés au gestionnaire de disposition avec une chaîne de caractères associée à chaque composant. Pour naviguer entre les cartes, on utilise les méthodes first(), last(), next(), previous() et show() de CardLayout.
La taille préférée d'un CardLayout est déterminée par la taille préférée du plus grand des composants qu'il gère. Il est très utile pour présenter des groupes de composants qui sont mutuellement exclusifs, comme des écrans différents au lieu d'un unique écran plus grand.
4. GridLayout : La Grille de Cellules Identiques

Ce Layout Manager établit un réseau de cellules identiques qui forment une sorte de quadrillage invisible : les composants sont organisés en lignes et en colonnes. Les éléments insérés dans la grille ont tous la même taille.
Lors de la construction d'un GridLayout, on spécifie le nombre de lignes et de colonnes. Si les deux valeurs sont différentes de zéro, le nombre de colonnes est ignoré (seul le nombre de lignes sera utilisé). Une bonne pratique de conception avec un GridLayout est de toujours mettre l'un des deux à zéro. Par exemple, si vous tenez absolument à avoir trois colonnes, spécifiez (0, 3).
La taille préférée d'un GridLayout est la plus grande largeur préférée et la plus grande hauteur préférée de tous les composants contenus, si possible. En effet, tous les composants dans un GridLayout doivent avoir la même taille.
5. GridBagLayout : La Grille Étendue et Flexible

Ce gestionnaire (grille étendue) est le plus riche en fonctionnalités : le conteneur est divisé en cellules égales mais un composant peut occuper plusieurs cellules de la grille et il est possible de faire une distribution dans des cellules distinctes. Les lignes et les colonnes prennent naissance au moment où les contrôles sont ajoutés.
Le GridBagLayout est le plus difficile à comprendre et peut occuper un livre entier. Vous devriez l'éviter autant que possible si la complexité n'est pas nécessaire. Cependant, il offre une flexibilité immense.
Pour utiliser GridBagLayout, on doit définir un ensemble de contraintes pour chaque composant ajouté (GridBagConstraints object constraints). Ces contraintes incluent des paramètres comme gridx, gridy (coordonnées de l'origine de la grille d'un composant), gridwidth, gridheight (largeur et hauteur en nombre de cellules), ipadx, et ipady (remplissage interne).
Ensuite, vous devez comprendre le paramètre remplissage (fill). Le paramètre fill permet de spécifier comment le composant doit remplir l'espace alloué : NONE (valeur par défaut, le composant ne s'étend pas), HORIZONTAL, VERTICAL, ou BOTH.

L'ancre (anchor) spécifie où le composant doit être aligné dans la cellule. La valeur par défaut est CENTER. Si un composant est plus petit que son espace alloué, peu importe son ancre, il sera ancré selon cette valeur. Par exemple, si vous voulez que votre composant soit en bas et au centre de sa cellule, son paramètre anchor doit être SOUTH.
Les encadrements (insets) définissent l'espace laissé autour des composants. Par défaut, les encadrements sont laissés à 0. Ils permettent de créer un espace vide entre un composant et les bords de sa cellule, ou entre lui et un autre composant voisin.
Enfin, les poids (weightx et weighty) contrôlent comment l'espace supplémentaire est distribué entre les composants lorsque le conteneur est redimensionné. Si la fenêtre est agrandie horizontalement, l'espace supplémentaire sera distribué proportionnellement aux weightx de chaque colonne. Par exemple, si les weightx des composants 1 et 2 doivent être égaux, on peut leur attribuer la même valeur. Une façon sympa consiste à faire que leur somme soit 1.0, mais ce n'est pas obligatoire.
Conception d'IUG Complexes avec Imbrication de Layout Managers
La véritable puissance des gestionnaires de disposition réside dans leur capacité à être imbriqués. On peut combiner plusieurs gestionnaires de disposition pour créer des IUG complexes. Par exemple, une IUG principale peut utiliser un BorderLayout, dont la partie NORTH pourrait contenir un FlowLayout pour des boutons, la partie WEST un GridLayout pour une liste d'options, et la partie CENTER un GridBagLayout pour un formulaire détaillé.

Imaginez une interface avec une zone d'en-tête, deux zones de contenu (gauche et droite), et un pied de page.Le conteneur principal est un panneau muni d'un BorderLayout. La partie NORTH pourrait contenir un JPanel avec un FlowLayout pour une barre de navigation. La partie SOUTH un autre JPanel avec un FlowLayout pour des informations de copyright. Les parties WEST et EAST pourraient être des JPanel structurées de manière similaire, utilisant un GridLayout ou un BorderLayout pour agencer des listes ou des boutons. La partie CENTER serait alors un JTextArea ou un autre JPanel complexe.
La clé est de visualiser la structure de l'IUG et de décomposer le problème en sous-IUG plus petites, chacune gérée par un gestionnaire de disposition approprié. Cette approche modulaire facilite grandement la conception et la maintenance de l'interface.
Activation et Désactivation des Composants
L'activation ou la désactivation d'un composant se fait grâce à sa méthode setEnabled(boolean). La valeur booléenne passée en paramètre indique l'état du composant (false : interdit l'usage du composant). Cela est utile pour contrôler les interactions de l'utilisateur en fonction du contexte de l'application.