Question

Nous constatons que la sélection JTable est annulée lorsque nous faisons un fireTableDataChanged () ou fireTableRowsUpdated () à partir du TableModel .

Est-ce attendu ou faisons-nous quelque chose de mal? Je n'ai vu aucune propriété de JTable (ou d'autres classes connexes) concernant la suppression / préservation de la sélection dans 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 et de réappliquer la sélection avant la mise à jour. C'est un peu lent.

Ceci est Java 1.4.2 sur Windows XP, si cela compte. Nous sommes limités à cette version en fonction du code de fournisseur que nous utilisons.

Était-ce utile?

La solution

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

Tout d'abord, vous devrez 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 souhaite souligner est que, si le nombre de lignes ou de colonnes de votre tableau augmente ou diminue après chaque rechargement du modèle de tableau, ne vous souciez pas de préserver la sélection.

L'utilisateur aurait pu sélectionner la rangée 2, colonne 1, avec la valeur "Canard", avant la mise à jour du modèle. Mais après la mise à jour du modèle, ces mêmes données peuvent maintenant apparaître dans la rangée 4, colonne 1, et votre rangée de cellule d'origine, colonne 2, pourrait contenir de nouvelles données telles que "Pig". Maintenant, si vous définissez de force la sélection sur ce qu'elle était avant la mise à jour du modèle, il se peut que ce ne soit pas ce que l'utilisateur souhaitait.

Ainsi, la sélection de cellules par programme pourrait être une arme à double tranchant. Ne le faites pas si vous n'êtes pas sûr.

Autres conseils

Vous pouvez conserver automatiquement la sélection d'une table si la STRUCTURE de cette table n'a pas changé (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 conservée à condition que seules les données, et non la structure de la table, aient été modifiées. La seule différence entre ceci et ce qui serait appelé si cette méthode n'était pas remplacée est que getRowCount () - 1 est passé pour l'argument lastRow au lieu d'Integer.MAX_VALUE, ce dernier servant de signifiant non seulement qu'il possède les données de la table ont changé mais le nombre de lignes peut aussi en avoir.

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 à des 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 de mettre à jour la liste. Une fois la liste modifiée et avant que le tableau ne soit mis à jour, je calculerais la position de l'objet sélectionné. S'il était toujours présent après la modification, je définirais la sélection sur le nouvel index.

Il ne suffit pas de définir l'index sélectionné dans le tableau après la modification, car l'objet peut changer de position dans la liste.

En remarque, j'ai constaté que travailler avec GlazedLists simplifie la vie beaucoup plus facilement avec les tableaux.

C'est le comportement par défaut. Si vous appelez fireTableDataChanged () , la table entière 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, puis de la définir. Malheureusement, rien ne garantit que la sélection sera toujours valide. Faites attention si vous restaurez la sélection.

pour référence, comme l'a dit @ Swapnonil Mukherjee, cela a fonctionné avec un tableau 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]);

Si je me souviens bien, enregistrer la sélection et la réappliquer est ce que nous avons fait aussi ...

J'étais confronté au même problème et lorsque j'ai essayé de rechercher la raison pour laquelle j'ai eu cette question, il semble un bogue dans le SDK Java. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

TRAVAILLER AUTOUR

Une solution temporaire est disponible. Il devrait être supprimé une fois ce bogue corrigé, car il n’a PAS été testé sur des versions corrigées.

Utilisez cette sous-classe de JTable.

Note: Ceci est pour le MetalLookAndFeel. Si vous utilisez une autre apparence, la sous-classe FixedTableUI interne devra étendre la sous-classe TableUI à cette apparence.

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 de Curtsey à http://bugs.sun.com

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top