Manipulation de JList par le clavier

Mon, 04/28/2008 - 10:53 — Serge Rosmorduc

J'ai un panneau avec deux listes, et je désire faire passer des éléments de l'une à l'autre. Une solution simple est bien entendu d'utiliser deux boutons. L'utilisateur souhaitera certainement pouvoir effectuer des sélections de manière différente:

Deux JLists

Je vais me contenter d'expliquer comment procéder pour l'un des deux panneaux.

On suppose que l'on a les déclarations suivantes :

 JList listeA; // objet graphique pour la première liste
 JList listeB; // objet graphique pour la seconde liste
 DefaultListModel modeleA; // modèle de la première liste
 DefaultListModel modele B; // modèle de la seconde liste

(comme mon but est d'expliquer la technique, je ne vais pas trop me soucier de la structure du code. Il est bien évident que je suggère fortement d'essayer de séparer un peu plus la partie où on a les JLists de celle qui contient les données).

Ces données sont initialisées :

listeA= new JList();
modeleA= new DefaultListModel();
listeA.setModel(modeleA);

idem pour B.

La méthode ‛transfertAVersB()‛ a pour fonction de transférer l'item sélectionné dans la liste A vers la liste B. Elle a la tête suivante:

public void transfertAVersB() {
  String item = (String) listeA.getSelectedValue(); // si le modèle contient des String
  if (item == null) // rien n'est sélectionné ?
    return;
  // Copie vers B
  modeleB.addElement(item);
  // Mise à jour de A (dans mon application, 
  //A était calculé à partir de B et de la liste totale des possibilités)
  modeleA.removeElement(item);
}

à partir de là, on met en place un bouton qui appelle ‛transfertAVersB‛, rien de bien méchant.

Pour que le double-clic ait le même effet, c'est assez facile, car lors d'un double clic, le premier clic sélectionne l'élément désiré. La précondition de transfertAVersB est alors remplie (l'élément à transférer est sélectionné).

listeA.addMouseListener(new MouseAdapter() {
  public void mouseClicked(MouseEvent e) {
    if (e.getClickCount() == 2) {
      transfertAversB();
    }
  }
});

L'activation de la barre d'espace est un peu plus acrobatique. En effet, rien ne garanti alors qu'un élément est effectivement sélectionné, et la documentation de JList n'explique pas franchement comment récupérer la position actuelle dans la liste.

En fait, quand il n'y a pas de zone sélectionnée, la position du curseur dans la liste est fournie par l'ancre (anchor) de la sélection. On utilisera donc le code suivant:

// Pour attacher une action "clavier" à un objet, la méthode conseillée est de passer par son inputMap.
// On procède en deux temps: on associe à la frappe clavier un nom d'action, puis on associe une action effective à ce nom.
listeA.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "a_vers_b");
listeA.getActionMap().put("a_vers_b", new AbstractAction() {
  public void actionPerformed(ActionEvent e) {
    // Même si rien n'est sélectionné, l'ancre aura toujours une valeur,
    // qui correspond à la position du curseur dans la liste
    int anchor= listeA.getAnchorSelectionIndex();
    // On force la sélection:
    listeA.setSelectedIndex(anchor);
    // On peut maintenant appeler transfertAVersB
    transfertAversB();
  }
});