
FAQ Java GUIConsultez toutes les FAQ
Nombre d'auteurs : 51, nombre de questions : 152, dernière mise à jour : 21 décembre 2009
Sommaire→AWT et Swing→Tableaux et arbres (JTable et JTree)- Comment rendre certaines cellules de ma JTable non éditables ?
- Comment faire des colonnes fixes dans une JTable ?
- Pourquoi les en-têtes de ma JTable ne s'affichent-ils pas ?
- Quelle cellule de ma JTable a été cliquée ?
- Comment ancrer les colonnes d'une JTable ?
- Comment sélectionner par programmation des lignes d'une JTable?
- Comment définir l'alignement (gauche, centre, droite, ...) du contenu des colonnes d'une JTable ?
- Qu'est ce qu'un JTree ?
- Comment construire un JTree ?
- Comment afficher la poignée du noeud racine ?
- Comment cacher le noeud racine ?
- Comment modifier les icônes d'un JTree ?
- Comment écouter les événements d'un JTree ?
- Comment modifier la méthode de séléction des noeuds d'un JTree ?
- Comment interdire de dérouler/enrouler un noeud ?
- Comment supprimer/modifier les icônes des noeuds parents ?
- Comment changer l'indentation entre les lignes ?
- Comment ne pas peindre les pointillés au début des lignes quand on utilise le L&F Windows ?
Pour que certaines cellules d'une JTable ne soient pas éditables, il faut créer sa propre classe dérivant de javax.swing.table.DefaultTableModel et redéfinir la méthode isCellEditable(int,int) afin que cette dernière retourne faux pour ces cellules.
public boolean isCellEditable (int row, int column) {
if ( celluleEstEditable ) {
return ( true );
} else {
return ( false );
}
}
Téléchargement : CustomTableModel1.java
On préférera un petit exemple à un long discours ;-)
Téléchargement : JTableFixedColumn.java
Les javax.swing.JTable sont prévus pour être affichés dans un JScrollPane, si ce n'est pas le cas l'en-tête n'est pas affiché. Pour l'afficher, vous pouvez récupérer l'en-tête en utilisant getTableHeader() et l'afficher séparément.
Un exemple est disponible ci-dessous.
Téléchargement : Exemple d'implémentation.
Il suffit d'utiliser les méthodes columnAtPoint(java.awt.Point) et rowAtPoint(java.awt.Point) en lui passant le paramètre récupéré sur l'évènement java.awt.event.MouseEvent
int colonne, ligne;
Point p = e.getPoint ();
colonne = jtable.columnAtPoint (p);
ligne = jtable.rowAtPoint (p);
Téléchargement : Exemple d'implémentation.
Il est parfois peu souhaitable que l'utilisateur puisse permuter les colonnes d'une javax.swing.JTable. Contre tout attente, la méthode permettant d'intervenir sur cette propriété n'est pas dans la classe JTable, mais dans la classe javax.swing.table.JTableHeader. Le code suivant permet d'annuler cette fonctionnalité.
maJTable.getTableHeader().setReorderingAllowed(false);
Il faut utiliser le SelectionModel de la JTable pour travailler sur la séléction de la JTable. Par exemple, pour selectionner les lignes 2,4 et 5 de la JTable myJTable:
myJTable.getSelectionModel().addSelectionInterval(2,2);
myJTable.getSelectionModel().addSelectionInterval(4,5);
Pour ce qui est de sélectionner des cellules ou des zones de cellules de la JTable, la méthode changeSelection est plus appropriée:
public void changeSelection(
int rowIndex,
int columnIndex,
boolean toggle,
boolean extend)
Il faut utiliser les méthodes setHorizontalAlignment() et setVerticalAlignment() de la classe DefaultTableCellRenderer (ces méthodes sont en fait héritées de la classe JLabel).
Exemple : création d'un DefaultTableCellRenderer qui centre le contenu des colonnes :
public class CenterTableCellRenderer extends DefaultTableCellRenderer {
public CenterTableCellRenderer() {
setHorizontalAlignment(CENTER);
setVerticalAlignment(CENTER);
}
}
Il faut ensuite appliquer le renderer aux colonnes de la JTable :
- Soit à toutes les colonnes de la table :
JTable table = new JTable();
// on applique le renderer à la table
table.setDefaultRenderer(Object.class, new CenterTableCellRenderer());
- Soit à une colonne en particulier :
// on applique le renderer à la colonne d'indice 0
table.getColumnModel().getColumn(0).setCellRenderer(new CenterTableCellRenderer());
On peut aussi faire de même pour les headers, cependant il vaut mieux récupérer le renderer par défaut et le modifier :
- Tous les headers :
// on applique le renderer sur tous les headers de la table
TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer());
((DefaultTableCellRenderer) headerRenderer).setHorizontalAlignment(DefaultTableCellRenderer.CENTER);
- Un header en particulier :
// on applique le renderer sur le header de la colonne d'indice 0
TableCellRenderer headerRenderer = table.getColumnModel().getColumn(0).getHeaderRenderer();
((DefaultTableCellRenderer) headerRenderer).setHorizontalAlignment(DefaultTableCellRenderer.CENTER);
Lien : La classe DefaultCellRendererLa classe DefaultCellRenderer
Un JTree est un composant Swing permettant d'afficher un arbre (une structure de donnée hiérarchique). Ce composant ne contient pas de données mais plutôt une vue de données contenues dans son modèle.
Lien : JTree
- Pour construire un JTree, il faut spécifier le modèle de l'arbre dans le constructeur.
- Il est posssible de créer son propre modèle en implémentant l'interface TreeModel ou bien en utilisant le modèle par défaut DefaultTreeModel.
DefaultTreeModel myModel = ...;JTree myTree = new JTree(myModel);
- Pour construire un modèle d'arbre par défaut, il est nécessaire de passer le noeud racine (root).
- Il est possible d'y passer tout objet implémentant l'interface TreeNode. Vous pouvez aussi utiliser la classe par défaut DefaultMutableTreeNode.
DefaultMutableTreeNode myRoot = ...;
DefaultTreeModel myModel = new DefaultTreeModel(myRoot);
- Pour créer un noeud, il faut indiquer un objet utilisateur. L'arbre utilisera le résultat de la méthode toString pour afficher une représentation de l'objet à un noeud donné. Pour un arbre représentant un système de fichiers, des objets File pourront être utilisés.
Voici un exemple simple et complet:
// Construction du noeud racine.
DefaultMutableTreeNode myRoot = new DefaultMutableTreeNode("Manuel");
// Construction des différents noeuds de l'arbre.
DefaultMutableTreeNode chap = new DefaultMutableTreeNode("Chapitre1");
myRoot.add(chap);
DefaultMutableTreeNode page = new DefaultMutableTreeNode("Page1");
chap.add(page);
page = new DefaultMutableTreeNode("Page2");
chap.add(page);
chap = new DefaultMutableTreeNode("Chapitre2");
myRoot.add(chap);
page = new DefaultMutableTreeNode("Page3");
chap.add(page);
// Construction du modèle de l'arbre.
DefaultTreeModel myModel = new DefaultTreeModel(myRoot);
// Construction de l'arbre.
JTree myTree = new JTree(myModel);
Par défaut, la poignée du noeud racine n'existe pas. Pour l'afficher, il faut ajouter la ligne suivante :
myTree.setShowsRootHandles(true);
Pour cacher le noeud racine, utile lorsque vous souhaitez afficher une forêt (un ensemble d'arbres), utilisez l'instruction suivante:
myTree.setRootVisible(false);
La méthode la plus simple consiste à construire un objet DefaultTreeCellRender puis de modifier les icônes et de l'appliquer à l'arbre.
// Construction d'un afficheur par défaut.
DefaultTreeCellRenderer myRenderer = new DefaultTreeCellRenderer();
// Changement de l'icône pour les feuilles de l'arbre.
myRenderer.setLeafIcon(new ImageIcon("pageIcon.png"));
// Changement de l'icône pour les noeuds fermés.
myRenderer.setClosedIcon(new ImageIcon("closedBookIcon.png"));
// Changement de l'icône pour les noeuds ouverts.
myRenderer.setOpenIcon(new ImageIcon("openBookIcon.png"));
// Application de l'afficheur à l'arbre.
myTree.setCellRenderer(myRenderer);
Deux autres solutions consistent à implémenter l'interface TreeCellRenderer ou bien à étendre la classe DefaultTreeCellRenderer, permettant ainsi de modifier les icônes, la police et la couleur de fond des différents noeuds de l'arbre.
De manière générale, le composant JTree ne s'utilise pas tout seul, un autre composant est utilisé pour afficher des informations relatives à l'objet utilisateur. Pour réaliser ce comportement, il est nécessaire de mettre en place un écouteur dit de sélection implémentant l'interface TreeSelectionListener sur l'arbre.
// Ajoute un événement de sélection à l'arbre.
myTree.addTreeSelectionListener(new TreeSelectionListener()
{
// Appelé lorsque la valeur de la sélection change.
public void valueChanged(TreeSelectionEvent event)
{
// Récupère le chemin dans l'arbre.
TreePath myPath = myTree.getSelectionPath();
if(myPath == null) return;
// Récupère l'objet utilisateur correspondant.
DefaultMutableTreeNode myNode = (DefaultMutableTreeNode) myPath.getLastPathComponent();
Page myPage = (Page) myNode.getUserObject();
myEditorPane().setPage(myPage.getUrl());
}
});
La méthode valueChanged de l'interface TreeSelectionListener est appelée lorsque l'utilisateur sélectionne ou désélectionne un des noeuds de l'arbre.
Il est possible de changer la méthode de sélection des noeuds de l'arbre avec la méthode setSelectionMode. Les différentes valeurs sont : SINGLE_TREE_SELECTION (sélection d'un seul noeud), CONTIGUOUS_TREE_SELECTION (sélection d'un ensemble contigus de noeuds), DISCONTIGUOUS_TREE_SELECTION (sélection d'un ensemble de noeuds). Exemple :
myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
On utilise l'écouteur adapté à cet effet et on renvoie une exception au comportement qu'on ne veut pas produire :
jtree.addTreeWillExpandListener(new TreeWillExpandListener(){
@Override
public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {}
@Override
public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException{
// On n'enroule pas le contenu du neoud quand on double-clique dessus
throw new ExpandVetoException(event);
}
});
Ici on interdit donc d'enrouler des noeuds.
En modifiant l'UI de l'arbre, il est tout à fait possible de modifier les icônes des arbres parents (aussi appelées poignées) :
((BasicTreeUI) ihmArbre.getUI()).setExpandedIcon(null);
((BasicTreeUI) ihmArbre.getUI()).setCollapsedIcon(null);
Ici, on les as supprimées, mais vous pouvez tout à fait les modifier.
Pour modifier l'indentation des éléments, on peut modifier l'UI de l'arbre :
((BasicTreeUI) jTree.getUI()).setRightChildIndent(0);
((BasicTreeUI) jTree.getUI()).setLeftChildIndent(0);
Ici on place les children au même niveau que les parents.
Il faut créer un nouveau BasicTreeUI et redéfinir les méthodes paintHorizontalPartOfLeg() et paintVerticalPartOfLeg pour indiquer qu'elles ne font rien :
jTree.setUI(new BasicTreeUI(){
protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) { }
protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) { }
});


















