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 |
Pour un dialogue d'ouverture de fichier, on appelle showOpenDialog(), et pour un dialogue de sauvegarde de fichier, on appelle showSaveDialog(). Ces commandes ne reviennent que lorsque le dialogue est fermé. L'objet JFileChooser existe encore, de sorte qu'on peut en lire les données. Les méthodes getSelectedFile() et getCurrentDirectory() sont deux façons d'obtenir les résultats de l'opération. Si celles-ci renvoient null, cela signifie que l'utilisateur a abandonné le dialogue.
Tout composant acceptant du texte peut également accepter du texte HTML, qu'il reformatera selon les règles HTML. Ceci signifie qu'on peut très facilement ajouter du texte de fantaisie à un composant Swing. Par exemple :
Le texte doit commencer avec , et ensuite on peut utiliser les tags HTML normaux. Remarquons que les tags de fermeture ne sont pas obligatoires.
L'ActionListener ajoute au formulaire un nouveau JLabel contenant du texte HTML. Comme ce label n'est pas ajouté dans la méthode init(), on doit appeler la méthode validate() du conteneur de façon à forcer une redisposition des composants (et de ce fait un affichage du nouveau label).
On peut également ajouter du texte HTML à un JTabbedPane, JMenuItem, JToolTip, JRadioButton ou un JCheckBox.
Un slider(qu'on a déjà utilisé dans l'exemple du sinus) permet à l'utilisateur de rentrer une donnée en déplaçant un point en avant ou en arrière, ce qui est intuitif dans certains cas (un contrôle de volume, par exemple). Un progress bar représente une donnée en remplissant proportionnellement un espace vide pour que l'utilisateur ait une idée de la valeur. Mon exemple favori pour ces composants consiste à simplement lier le curseur à la barre de progression, de sorte que lorsqu'on déplace le curseur la barre de progression change en conséquence :
La clé du lien entre les deux composant se trouve dans le partage de leur modèle, dans la ligne :
Naturellement, on pourrait aussi contrôler les deux composants en utilisant un listener, mais ceci est plus direct pour les cas simples.
Le JProgressBar est assez simple, mais le JSlidera un grand nombre d'options, telles que l'orientation et les graduations mineures et majeures. Remarquons la simplicité de l'ajout d'une bordure avec titre.
L'utilisation d'un JTreepeut être aussi simple que ceci :
Ceci affiche un arbre rudimentaire. L'API pour les arbres est vaste, probablement une des plus importantes de Swing. On peut faire à peu près tout ce qu'on veut avec des arbres, mais les tâches plus complexes demandent davantage de recherches et d'expérimentations.
Heureusement, il y a un niveau intermédiaire fourni dans la bibliothèque : les composants arbres par défaut, qui font en général ce dont on a besoin, de sorte que la plupart du temps on peut se contenter de ces composants, et ce n'est que dans des cas particuliers qu'on aura besoin d'approfondir et de comprendre plus en détail les arbres.
L'exemple suivant utilise les composants arbres par défaut pour afficher un arbre dans une applet. Lorsqu'on appuie sur le bouton, un nouveau sous-arbre est ajouté sous le noeud sélectionné (si aucun noeud n'est sélectionné, le noeud racine est utilisé) :
La première classe, Branch, est un outil qui prend un tableau et construit un DefaultMutableTreeNodeavec la première String comme racine, et le reste des Strings du tableau pour les feuilles. Ensuite node() peut être appelé pour créer la racine de cette branche.
La classe Trees contient un tableau de Strings à deux dimensions à partir duquel des Branches peuvent être créées, ainsi qu'un static int i pour servir d'index à travers ce tableau. L'objet DefaultMutableTreeNode contient les noeuds, mais la représentation physique à l'écran est contrôlée par le JTree et son modèle associé, le DefaultTreeModel. Notons que lorsque le JTree est ajouté à l'applet, il est encapsulé dans un JScrollPane : c'est suffisant pour permettre un scrolling automatique.
Le JTree est contrôlé par son modèle. Lorsqu'on modifie les données du modèle, celui-ci génère un événement qui force le JTree à effectuer les mises à jour nécessaires de la partie visible de la représentation de l'arbre. Dans init(), le modèle est obtenu par appel à getModel(). Lorsqu'on appuie sur le bouton, une nouvelle branche est créée. Ensuite le composant actuellement sélectionné est recherché (on utilise la racine si rien n'est sélectionné) et la méthode insertNodeInto() du modèle effectue la modification de l'arbre et provoque sa mise à jour.
Un exemple comme ci-dessus peut vous donner ce dont vous avez besoin pour utiliser un arbre. Cependant les arbres ont la possibilité de faire à peu près tout ce qui est imaginable ; chaque fois que le mot default apparaît dans l'exemple ci-dessus, on peut y substituer sa propre classe pour obtenir un comportement différent. Mais attention : la plupart de ces classes a une interface importante, de sorte qu'on risque de passer du temps à comprendre la complexité des arbres. Cependant, on a affaire ici à une bonne conception, et les autres solutions sont en général bien moins bonnes.
Comme les arbres, les tables en Swing sont vastes et puissantes. Elles sont destinées principalement à être la populaire grille d'interface avec les bases de données via la Connectivité Bases de Données Java : Java DataBase Connectivity (JDBC, présenté dans le Chapitre 15) et pour cela elles ont une flexibilité énorme, que l'on paie en complexité. Il y a ici suffisamment pour servir de base à un tableur complet et pourrait probablement être le sujet d'un livre complet. Cependant, il est également possible de créer une name="Index1768">JTablerelativement simple si on en comprend les bases.
La JTable contrôle la façon dont les données sont affichées, tandis que le TableModel contrôle les données elles-mêmes. Donc pour créer une JTable on créera d'abord un TableModel. On peut implémenter complètement l'interface TableModel, mais il est souvent plus simple d'hériter de la classe utilitaire AbstractTableModel :
DataModelcontient un tableau de données, mais on pourrait aussi obtenir les données depuis une autre source telle qu'une base de données. Le constructeur ajoute un TableModelListener qui imprime le tableau chaque fois que la table est modifiée. Les autres méthodes suivent les conventions de nommage des Beans ; elles sont utilisées par la JTable lorsqu'elle veut présenter les informations contenues dans DataModel. AbstractTableModel fournit des méthodes par défaut pour setValueAt() et isCellEditable() qui interdisent les modifications de données, de sorte que ces méthodes devront être redéfinies si on veut pouvoir modifier les données.
Une fois obtenu un TableModel, il suffit de le passer au constructeur de la JTable. Tous les détails concernant l'affichage, les modifications et la mise à jour seront automatiquement gérés. Cet exemple place également la JTable dans un JScrollPane.
Un des aspects très intéressants de Swing est le name="Index1770">Pluggable Look & Feel. Il permet à un programme d'émuler le look and feel de divers environnements d'exploitation. On peut même faire toutes sortes de choses comme par exemple changer le look and feel pendant l'exécution du programme. Toutefois, en général on désire soit sélectionner le look and feel toutes plateformes (qui est le Metal de Swing), soit sélectionner le look and feel du système courant, de sorte à donner l'impression que le programme Java a été créé spécifiquement pour ce système. Le code permettant de sélectionner chacun de ces comportements est assez simple, mais il faut l'exécuter avant de créer les composants visuels, car ceux-ci seront créés selon le look and feel courant et ne seront pas changés par le simple changement de look and feel au milieu du programme (ce processus est compliqué et peu banal, et nous en laisserons le développement à des livres spécifiques sur Swing).
En fait, si on veut utiliser le look and feel toutes plateformes (metal) qui est la caractéristique des programmes Swing, il n'y a rien de particulier à faire, c'est la valeur par défaut. Si au contraire on veut utiliser le look and feel de l'environnement d'exploitation courant, il suffit d'insérer le code suivant, normalement au début du main() mais de toutes façons avant d'ajouter des composants :
Il n'y a pas besoin de faire quoi que ce soit dans la clause catch car le UIManager se positionnera par défaut au look and feel toutes plateformes si votre tentative d'installation d'un des autres échoue. Toutefois, pour le debug, l'exception peut être utile, de sorte qu'on peut au minimum placer une instruction d'impression dans la clause catch.
Voici un programme qui utilise un argument de ligne de commande pour sélectionner un look and feel, et montre à quoi ressemblent différents composants dans le look and feel choisi :