|
Swing - Interface Homme-Machine
5.8.JTable
JTable est un composant extrêmement utile mais malheureusement assez complexe. En effet un package complet, nommé javax.swing.table lui est consacré. Le composant JTable permet d’afficher des tables de données, en permettant éventuellement l’édition de ces données. Un JTable ne contient pas ses données mais les obtient à partir d’un tableau d’objets à 2 dimensions, ou à partir d’un modèle de données. Nous étudierons ici assez brièvement ce package, mais il ne faut pas oublier que ce dernier intègre diverses fonctionnalités que nous n’étudierons pas ici telles que l’impression et l’affichage avant impression, les interactions client-serveur à l’aide de CORBA… Exemple de JTable :
La classe JTable implémente l’interface Scrollable (ce qui signifie qu’il peut être placé dans un JScrollPane) . Chaque JTable dispose de trois modèles qui sont :
TableModel définit la manière dont sont stockées les données, et gèrées les ajouts et suppressions ainsi que la récupération des données. Il définit aussi les types de données de chaque colonne, et spécifie aussi si une cellule est éditable. Toutes les données de la table sont stockées dans le TableModel (tableau à 2 dimension ou vecteur de vecteurs). TableColumnModel gère des instances de TableColumn (c'est-à-dire une colonne de la table). TableColumnModel est responsable de l’affichage des colonnes dans la table. Chaque TableColumn possède un cell renderer, un cell editor, un table header, et un cell renderer pour le table header. ListSelectionModel définit le mode de sélection (single-interval, multiple-interval). ListSelectionModel est très flexible et permet de personnaliser les sélections de toutes les manières que l’on souhaite.
5.8.1.Utilisation simple d’une JTable
La méthode la plus simple pour construire une table est de passer un vecteur de vecteurs en paramètres du constructeur. Le constructeur suivant va être utilisé :
- JTable (Vector rowData, Vector columnNames)
Ce constructeur reçoit des vecteurs de vecteurs (rowData pour les lignes, columnNames pour les entêtes). Pour pouvoir ensuite afficher la table il est préférable d’utiliser l’interface Scrollable implémentée par JTable. JScrollPane sp = new JScrollPane(table);
5.8.2.Renderers par défaut
Nous allons nous intéresser ici à un mécanisme particulièrement utile qui est celui de l’utilisation des renderers. En l’occurrence il va s’agir ici de DefaultTableCellRenderer. Le principe est de s’appuyer sur les renderers par défaut. Pour cela la JTable doit connaître le type de données à afficher, il va s’adresser à l’objet qui encapsule les données, c'est-à-dire le TableModel. Il y a alors deux cas possible :
- Il n’existe pas de TableModel crée par l’utilisateur. JTable utilise le TableModel crée par défaut.
Demande au modèle quel est le type des objets contenus dans la colonne i : Modele.getColumnClass(i)
L’implémentation par défaut renvoie toujours la classe Object
- Si il existe un TableModel personnalisé, alors la JTable s’adresse à ce dernier.
Demande au modèle quel est le type des objets contenus dans la colonne i : Modele.getColumnClass(i)
La fonction getColumnClass redéfinie renvoie le type exact de la donnée à afficher.
Une fois que JTable connaît le type de données à afficher, il se réfère à son dictionnaire liant les types et leurs renderers associés. Ce dictionnaire est la classe suivante : protected Hashtable defaultRenderersByColumnClass Ce dictionnaire contient par défaut la liste suivante :
- Boolean (JCheckbox)
- Number (JLabel aligné à droite)
- Date (JLabel formaté avec DateFormat et aligné à droite)
- ImageIcon (JLabel aligné au centre)
- Object (JLabel aligné à gauche affichant une chaîne de caractères)
Il va donc s’agir de redéfinir un TableModel pour notre JTable et de lui inclure la méthode qui renvoie le type d’objet : public class getColumnClass(int colonne) { return getValueAt(0, colonne).getClass(); }
5.8.3.Les Editors
Comme on a pu le constater, par défaut les cellules d’une JTable sont éditables. Par contre, lorsque l’on utilise un renderer personnalisé, on peut choisir de rendre le tableau non éditable. Il est souvent possible que l’on cherche à mettre en place une manière précise d’éditer une cellule, par exemple de faire apparaître une JList où l’on doit sélectionner une valeur.
5.8.4.Fonctionnement des Editors
Le fonctionnement des editors est très similaire à celui des renderers. Lorsque l’utilisateur cherche à modifier le contenu d’une cellule (double clic, saisie clavier), l’editor prend le contrôle sur la cellule. Voici le fonctionnement des Editors :
Demande à l’editor comment gérer la cellule (i,j) que l’utilisateur souhaite éditer
Renvoie le composant graphique entièrement paramétré
Comme dans le cas des renderers, on est assez libre dans l’implémentation. On peut choisir d’hériter d’un composant graphique (extends JLabel ….), ou bien d’encapsuler ce composant dans une variable d’instance. Il est toutefois indispensable d’implémenter l’interface en question (ici CellEditor). La figure ci-dessous présente la hiérarchie des classes editor.
On peut remarquer qu’il n’existe pas de classe de type ListCellEditor (ce qui est logique car JList n’est pas un composant éditable). La classe DefaultCellEditor peut être utilisée pour les tables et pour les arbres car elle hérite des deux interfaces TableCellEditor et TreeCellEditor. Il existe néanmoins une classe plus adaptée à l’édition d’un arbre, qui est DefaultTreeCellEditor.
5.8.5.Créer notre Editor
Pour illustrer l’implémentation d’un editor appliqué à notre exemple précédent, on considère que l’utilisateur doit choisir une ville dans une liste déroulante. Une manière simple de créer un editor est d’utiliser la classe DefaultCellEditor. Celle-ci encapsule le composant graphique sous la forme d’une variable nommée editorComponent. Il est possible d’afficher un JTextField, une JCheckBox ou encore une JComboBox. DefaultCellEditor dispose de constructeurs permettant d’accepter chacun des composants précités. Object[] villes = {"Paris", "Venise", "Mexico", "Toulouse", "Bordeaux"}; JComboBox cboVilles = new JComboBox(villes); DefaultCellEditor monEditor = new DefaultCellEditor(cboVilles); TableColumn col3 = table.getColumnModel().getColumn(3); col3.setCellEditor(monEditor); Une autre manière de créer un editor personnalisé consiste à hériter de AbstractCellEditor, et d’implémenter les fonctions getTableCellEditorComponent() et getCellEditorValue(). En voici un exemple : class EditorPerso extends AbstractCellEditor implements TableCellEditor { public JTextField monChamp; public EditorPerso() { monChamp = new JTextField(); monChamp.setBackground(Color.GREEN); } public Component getTableCellEditorComponent (JTable table, Object value, boolean isSelected, int row, int column) { monChamp.setText((String) value); return monChamp; } public Object getCellEditorValue() { String a = monChamp.getText(); return a; } }
|
|
 |