Penser en Java 2nde édition | - | Sommaire | Préface | Avant-propos | Chapitre : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Annexe : A B C D | Tables des matières | - | Thinking in Java |
Dans init(), addActionListener() est utilisée pour enregistrer l'objet BL pour chacun des boutons.
Il est souvent plus pratique de coder l'ActionListener comme une classe anonyme interne [anonymous inner class], particulièrement lorsqu'on a tendance à n'utiliser qu'une seule instance de chaque classe listener. Button2.java peut être modifié de la façon suivante pour utiliser une classe interne anonyme :
L'utilisation d'une classe anonyme interne sera préférée (si possible) pour les exemples de ce livre.
Un JTextArea est comme un JTextField, sauf qu'il peut avoir plusieurs lignes et possède plus de fonctionnalités. Une méthode particulièrement utile est append(); avec cette méthode on peut facilement transférer une sortie dans un JTextArea, faisant de ce fait d'un programme Swing une amélioration (du fait qu'on peut scroller en arrière) par rapport à ce qui a été fait jusqu'ici en utilisant des programmes de ligne de commande qui impriment sur la sortie standard. Comme exemple, le programme suivant remplit un JTextArea avec la sortie du générateur geography du chapitre 9 :
Dans init(), le Map est rempli avec tous les pays et leurs capitales. Remarquons que pour chaque bouton l'ActionListener est créé et ajouté sans définir de variable intermédiaire, puisqu'on n'aura plus jamais besoin de s'y référer dans la suite du programme. Le bouton "Add Data" formate et ajoute à la fin toutes les données, tandis que le bouton "Clear Data" utilise setText() pour supprimer tout le texte du JTextArea.
Lors de l'ajout du JTextArea à l'applet, il est enveloppé dans un JScrollPane, pour contrôler le scrolling quand trop de texte est placé à l'écran. C'est tout ce qu'il y a à faire pour fournir des fonctionnalités de scrolling complètes. Ayant essayé d'imaginer comment faire l'équivalent dans d'autres environnements de programmation de GUI, je suis très impressionné par la simplicité et la bonne conception de composants tels que le JScrollPane.
La façon dont on place les composants sur un formulaire en Java est probablement différente de tout système de GUI que vous avez utilisé. Premièrement, tout est dans le code ; il n'y a pas de ressources qui contrôlent le placement des composants. Deuxièmement, la façon dont les composants sont placés dans un formulaire est contrôlée non pas par un positionnement absolu mais par un layout manager qui décide comment les composants sont placés, selon l'ordre dans lequel on les ajoute ( add() ). La taille, la forme et le placement des composants seront notablement différents d'un layout manager à l'autre. De plus, les gestionnaires de disposition s'adaptent aux dimensions de l'applet ou de la fenêtre de l'application, de sorte que si la dimension de la fenêtre est changée, la taille, la forme et le placement des composants sont modifiés en conséquence.
JApplet, JFrame, JWindow et JDialog peuvent chacun fournir un Container avec getContentPane() qui peut contenir et afficher des Components. Dans Container, il y a une méthode appelée setLayout() qui permet de choisir le layout manager. D'autres classes telles que JPanel contiennent et affichent des composants directement, et donc il faut leur imposer directement le layout manager, sans utiliser le content pane.
Dans cette section nous allons explorer les divers gestionnaires de disposition en créant des boutons (puisque c'est ce qu'il y a de plus simple). Il n'y aura aucune capture d'événements de boutons puisque ces exemples ont pour seul but de montrer comment les boutons sont disposés.
L'applet utilise un layout manager par défaut : le BorderLayout (certains des exemples précédents ont modifié le layout manager par défaut pour FlowLayout). Sans autre information, il prend tout ce qu'on lui ajoute ( add() ) et le place au centre, en étirant l'objet dans toutes les directions jusqu'aux bords.
Cependant le BorderLayout ne se résume pas qu'à cela. Ce layout manager possède le concept d'une zone centrale et de quatre régions périphériques. Quand on ajoute quelque chose à un panel qui utilise un BorderLayout, on peut utiliser la méthode add() surchargée qui prend une valeur constante comme premier argument. Cette valeur peut être une des suivantes :
BorderLayout.NORTH (en haut) BorderLayout.SOUTH (en bas) BorderLayout.EAST (à droite) BorderLayout.WEST (à gauche) BorderLayout.CENTER (remplir le milieu, jusqu'aux autres composants ou jusqu'aux bords)
Si aucune région n'est spécifiée pour placer l'objet, le défaut est CENTER.
Voici un exemple simple. Le layout par défaut est utilisé, puisque JApplet a BorderLayout par défaut :
Pour chaque placement autre que CENTER, l'élément qu'on ajoute est comprimé pour tenir dans le plus petit espace le long d'une dimension et étiré au maximum le long de l'autre dimension. CENTER, par contre, s'étend dans chaque dimension pour occuper le milieu.
Celui-ci aligne simplement les composants sur le formulaire, de gauche à droite jusqu'à ce que l'espace du haut soit rempli, puis descend d'une rangée et continue l'alignement.
Voici un exemple qui positionne le layout manager en FlowLayout et place ensuite des boutons sur le formulaire. On remarquera qu'avec FlowLayout les composants prennent leur taille naturelle. Un JButton, par exemple, aura la taille de sa chaîne.
Tous les composants sont compactés à leur taille minimum dans un FlowLayout, ce qui fait qu'on peut parfois obtenir un comportement surprenant. Par exemple, vu qu'un JLabel prend la taille de sa chaîne, une tentative de justifier à droite son texte ne donne pas de modification de l'affichage dans un FlowLayout.
Un GridLayout permet de construire un tableau de composants, et lorsqu'on les ajoute ils sont placés de gauche à droite et de haut en bas dans la grille. Dans le constructeur on spécifie le nombre de rangées et de colonnes nécessaires, et celles-ci sont disposées en proportions identiques.
Dans ce cas il y a 21 cases mais seulement 20 boutons. La dernière case est laissée vide car il n'y a pas d'équilibrage dans un GridLayout.
Le GridBagLayoutnous donne un contrôle fin pour décider exactement comment les régions d'une fenêtre vont se positionner et se replacer lorsque la fenêtre est redimensionnée. Cependant, c'est aussi le plus compliqué des layout managers, et il est assez difficile à comprendre. Il est destiné principalement à la génération de code automatique par un constructeur d'interfaces utilisateurs graphiques [GUI builder] (les bons GUI builders utilisent GridBagLayout plutôt que le placement absolu). Si votre modèle est compliqué au point que vous sentiez le besoin d'utiliser le GridBagLayout, vous devrez dans ce cas utiliser un outil GUI builder pour générer ce modèle. Si vous pensez devoir en connaître les détails internes, je vous renvoie à Core Java 2 par Horstmann & Cornell (Prentice-Hall, 1999), ou un livre dédié à Swing, comme point de départ.
Il est également possible de forcer la position absolue des composants graphiques de la façon suivante :
Certains GUI builders utilisent cette approche de manière extensive, mais ce n'est en général pas la meilleure manière de générer du code. Les GUI builders les plus efficaces utilisent plutôt GridBagLayout.
Les gens ayant tellement de problèmes pour comprendre et utiliser GridBagLayout, Swing contient également le BoxLayout, qui offre la plupart des avantages du GridBagLayout sans en avoir la complexité, de sorte qu'on peut souvent l'utiliser lorsqu'on doit coder à la main des layouts (encore une fois, si votre modèle devient trop compliqué, utilisez un GUI builder qui générera les GridBagLayouts à votre place). BoxLayout permet le contrôle du placement des composants soit verticalement soit horizontalement, et le contrôle de l'espace entre les composants en utilisant des choses appelées struts (entretoises) et glue (colle). D'abord, voyons comment utiliser BoxLayout directement, en faisant le même genre de démonstration que pour les autres layout managers :
Le constructeur du BoxLayout est un peu différent des autres layout managers : on fournit le Container que le BoxLayout doit contrôler comme premier argument, et la direction du layout comme deuxième argument.
Pour simplifier les choses, il y a un container spécial appelé Box qui utilise BoxLayout comme manager d'origine. L'exemple suivant place les composants horizontalement et verticalement en utilisant Box, qui possède deux méthodes static pour créer des boxes avec des alignements verticaux et horizontaux :
Une fois qu'on a obtenu un Box, on le passe en second argument quand on ajoute des composants au content pane.
Les struts ajoutent de l'espace entre les composants, mesuré en pixels. Pour utiliser un strut, on l'ajoute simplement entre les ajouts de composants que l'on veut séparer :