2008-10-31 10 views
14

Nous voyons JTable sélection être effacé lorsque nous faisons un fireTableDataChanged() ou fireTableRowsUpdated() du TableModel.Conserver la sélection JTable à travers TableModel changement

Est-ce prévu ou faisons-nous quelque chose de mal? Je n'ai vu aucune propriété sur le JTable (ou d'autres classes connexes) sur la suppression/préservation de la sélection sur les mises à jour du modèle.

S'il s'agit d'un comportement par défaut, existe-t-il un bon moyen de l'éviter? Peut-être un moyen de "verrouiller" la sélection avant la mise à jour et déverrouiller après?

Le développeur a essayé d'enregistrer la sélection avant sa mise à jour et de la réappliquer. C'est un peu lent.

Java 1.4.2 sur Windows XP, si cela est important. Nous sommes limités à cette version basée sur un code de fournisseur que nous utilisons.

Répondre

4

Vous devez conserver la sélection, puis ré-appliquer.

Tout d'abord vous aurez besoin d'obtenir une liste de toutes les cellules sélectionnées.

Ensuite, lorsque vous rechargez la JTable avec les nouvelles données, vous devez réappliquer par programme ces mêmes sélections.

L'autre point que je veux faire est, si le nombre ou les lignes ou les colonnes dans votre table augmentent ou diminuent après chaque recharge de modèle de table, alors ne vous souciez pas de préserver la sélection.

L'utilisateur pourrait avoir sélectionné la colonne 1 de la ligne 2 ayant une valeur "canard", avant la mise à jour du modèle. Mais après la mise à jour du modèle, les mêmes données peuvent désormais apparaître dans la colonne 1 de la ligne 4, et la colonne 1 de la rangée 1 de la cellule d'origine pourrait contenir de nouvelles données telles que "Pig". Maintenant, si vous définissez forcément la sélection sur ce qu'elle était avant la mise à jour du modèle, ce n'est peut-être pas ce que l'utilisateur voulait. Par conséquent, la sélection par programme de cellules peut être une épée à double tranchant. Ne le faites pas, si vous n'êtes pas sûr.

0

Si je me souviens bien, l'enregistrement et la sélection d'une nouvelle demande est ce que nous avons fait trop ...

1

C'est le comportement par défaut. Si vous appelez fireTableDataChanged(), l'intégralité de la table est reconstruite à partir de zéro lorsque vous définissez un nouveau modèle. Dans ce cas, la sélection est, naturellement, perdue. Si vous appelez fireTableRowsUpdated(), la sélection est également effacée dans les cas généraux. Le seul moyen est de se souvenir de la sélection et de la définir ensuite. Malheureusement, il n'y a aucune garantie que la sélection sera toujours valide. Soyez prudent si vous restaurez la sélection.

0

J'ai eu le même problème dans une application. Dans mon cas, le modèle dans la table était une liste d'objets, où les propriétés de l'objet étaient mappées aux colonnes. Dans ce cas, lorsque la liste a été modifiée, j'ai récupéré l'index sélectionné et stocké l'objet sélectionné avant la mise à jour de la liste. Une fois la liste modifiée et avant que la table ne soit mise à jour, je calcule la position de l'objet sélectionné. S'il était encore présent après la modification, alors je placerais la sélection au nouvel index.

Le simple paramétrage de l'index sélectionné dans la table après la modification ne fonctionnera pas, car l'objet peut changer de position dans la liste.

En note, j'ai trouvé que travailler avec GlazedLists rend la vie beaucoup plus facile quand il s'agit de tables.

4

Vous pouvez conserver automatiquement la sélection d'une table si la STRUCTURE de cette table n'a pas été modifiée (c'est-à-dire si vous n'avez pas ajouté/supprimé de colonnes/lignes) comme suit.

Si vous avez écrit votre propre implémentation de TableModel, vous pouvez simplement remplacer la méthode fireTableDataChanged():

 @Override 
     public void fireTableDataChanged() { 
      fireTableChanged(new TableModelEvent(this, //tableModel 
               0, //firstRow 
               getRowCount() - 1, //lastRow 
               TableModelEvent.ALL_COLUMNS, //column 
               TableModelEvent.UPDATE)); //changeType 
     } 

et cela devrait vous assurer que votre sélection est automatiquement à condition que seules les données et non pas la structure de la table a changé. La seule différence entre ceci, et ce qui serait appelé si cette méthode n'était pas substituée est que getRowCount() - 1 est passé pour l'argument lastRow au lieu de Integer.MAX_VALUE, ce dernier qui agit comme un signifiant qui non seulement a tous les les données de la table ont changé mais que le nombre de lignes peut également avoir.

+0

méfiez-vous: faire pourrait se retourner contre - un dataChanged peut inclure des insertions/suppressions. Si c'est le cas, les auditeurs pourraient être gravement induits en erreur. – kleopatra

+0

Cela ne serait-il pas une structureChanged alors? –

+0

non, une structureChanged est lorsque les colonnes sont modifiées avec les données – kleopatra

0

Je faisais face au même problème et quand essayé de chercher la raison pour laquelle j'ai eu cette question, mais il semble que ce soit un bug dans Java SDK. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

AUTOUR DE TRAVAIL

Un travail autour temporaire est disponible. Il devrait être supprimé une fois que ce bogue a été corrigé car il n'a PAS été testé par rapport aux versions corrigées.

Utilisez cette sous-classe de JTable.

Remarque: Ceci est pour le MetalLookAndFeel. Si vous utilisez d'autres aspects, la sous-classe FixedTableUI interne devra étendre la sous-classe TableUI pour ce look and feel.

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.table.*; 
import javax.swing.event.*; 
import javax.swing.plaf.basic.*; 

public class FixedTable extends JTable { 

    private boolean isControlDownInDrag; 

    public FixedTable(TableModel model) { 
     super(model); 
     setUI(new FixedTableUI()); 
    } 

    private class FixedTableUI extends BasicTableUI { 
     private MouseInputHandler handler = new MouseInputHandler() { 
      public void mouseDragged(MouseEvent e) { 
       if (e.isControlDown()) { 
        isControlDownInDrag = true; 
       } 
       super.mouseDragged(e); 
      } 

      public void mousePressed(MouseEvent e) { 
       isControlDownInDrag = false; 
       super.mousePressed(e); 
      } 

      public void mouseReleased(MouseEvent e) { 
       isControlDownInDrag = false; 
       super.mouseReleased(e); 
      } 
     }; 

     protected MouseInputListener createMouseInputListener() { 
      return handler; 
     } 
    } 

    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { 
     if (isControlDownInDrag) { 
      ListSelectionModel rsm = getSelectionModel(); 
      ListSelectionModel csm = getColumnModel().getSelectionModel(); 

      int anchorRow = rsm.getAnchorSelectionIndex(); 
      int anchorCol = csm.getAnchorSelectionIndex(); 

      boolean anchorSelected = isCellSelected(anchorRow, anchorCol); 

      if (anchorSelected) { 
       rsm.addSelectionInterval(anchorRow, rowIndex); 
       csm.addSelectionInterval(anchorCol, columnIndex); 
      } else { 
       rsm.removeSelectionInterval(anchorRow, rowIndex); 
       csm.removeSelectionInterval(anchorCol, columnIndex); 
      } 

      if (getAutoscrolls()) { 
       Rectangle cellRect = getCellRect(rowIndex, columnIndex, false); 
       if (cellRect != null) { 
        scrollRectToVisible(cellRect); 
       } 
      } 
     } else { 
      super.changeSelection(rowIndex, columnIndex, toggle, extend); 
     } 
    } 
} 

Remarque Curtsey à http://bugs.sun.com

1

pour référence, @Swapnonil Mukherjee a déclaré, ce fait le tour d'une table avec des lignes sélectionnables:

 // preserve selection calling fireTableDataChanged() 
     final int[] sel = table.getSelectedRows(); 

     fireTableDataChanged(); 

     for (int i=0; i<sel.length; i++) 
      table.getSelectionModel().addSelectionInterval(sel[i], sel[i]);