Pregunta

Estamos viendo que se borra la selección de JTable cuando hacemos un fireTableDataChanged () o fireTableRowsUpdated () del TableModel .

¿Es esto esperado, o estamos haciendo algo mal? No vi ninguna propiedad en el JTable (u otras clases relacionadas) sobre la eliminación / preservación de la selección en las actualizaciones del modelo.

Si este es el comportamiento predeterminado, ¿hay una buena manera de evitarlo? Tal vez alguna forma de " bloquear " la selección antes de la actualización y desbloquear después?

El desarrollador ha estado experimentando con guardar la selección antes de la actualización y volver a aplicarla. Es un poco lento.

Esto es Java 1.4.2 en Windows XP, si eso importa. Estamos limitados a esa versión en función del código de proveedor que usamos.

¿Fue útil?

Solución

Debe conservar la selección y volver a aplicarla.

En primer lugar, deberá obtener una lista de todas las celdas seleccionadas.

Luego, cuando vuelve a cargar la JTable con los nuevos datos, necesita volver a aplicar esas mismas selecciones mediante programación.

El otro punto que quiero señalar es que si el número o las filas o columnas de su tabla aumentan o disminuyen después de cada recarga de cada modelo de tabla, no se moleste en conservar la selección.

El usuario podría haber seleccionado la fila 2 de la columna 1 con un valor que diga " Duck " ;, antes de la actualización del modelo. Pero después de la actualización del modelo, esos mismos datos ahora pueden ocurrir en la fila 4, columna 1, y su celda original, fila 2, columna 1 podría tener nuevos datos como " Pig " ;. Ahora, si establece la selección a la fuerza según lo que era antes de la actualización del modelo, puede que esto no sea lo que el usuario deseaba.

Por lo tanto, la selección programada de celdas podría ser una espada de doble filo. No lo hagas, si no estás seguro.

Otros consejos

Puede conservar automáticamente la selección de una tabla si la ESTRUCTURA de esa tabla no ha cambiado (es decir, si no ha agregado / eliminado ninguna columna / fila) de la siguiente manera.

Si ha escrito su propia implementación de TableModel, simplemente puede anular el método fireTableDataChanged ():

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

y esto debería garantizar que su selección se mantenga siempre que solo hayan cambiado los datos y no la estructura de la tabla. La única diferencia entre esto, y lo que se llamaría si este método no se anulara es que getRowCount () - 1 se pasa por el argumento lastRow en lugar de Integer.MAX_VALUE, el último de los cuales actúa como un significante que no solo tiene todos los los datos en la tabla cambiaron, pero eso también puede tener el número de filas.

Tuve el mismo problema en una aplicación. En mi caso, el modelo en la tabla era una lista de objetos, donde las propiedades del objeto se asignaban a columnas. En ese caso, cuando se modificó la lista, recuperé el índice seleccionado y almacené el objeto seleccionado antes de actualizar la lista. Después de modificar la lista y antes de actualizar la tabla, calcularía la posición del objeto seleccionado. Si todavía estaba presente después de la modificación, establecería la selección en el nuevo índice.

El solo hecho de configurar el índice seleccionado en la tabla después de la modificación no funcionará, ya que el objeto puede cambiar de posición en la lista.

Como nota al margen, descubrí que trabajar con GlazedLists hace que la vida sea mucho más fácil cuando se trata de tablas.

Este es el comportamiento predeterminado. Si llama a fireTableDataChanged () , la tabla completa se reconstruirá desde cero mientras establece un modelo completamente nuevo. En este caso la selección es, naturalmente, perdida. Si llama a fireTableRowsUpdated () , la selección también se desactiva en los casos generales. La única forma es recordar la selección y luego configurar esto. Lamentablemente, no hay garantía de que la selección siga siendo válida. Tenga cuidado si se restaura la selección.

para referencia, como @Swapnonil Mukherjee dijo, esto funcionó con una tabla con filas seleccionables:

        // 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 recuerdo correctamente, guardar la selección y volver a aplicar es lo que hemos hecho también ...

Estaba enfrentando el mismo problema y cuando intenté buscar el motivo, obtuve esta pregunta, pero parece un error en el SDK de Java. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

TRABAJAR ALREDEDOR

Hay una solución temporal disponible. Debe eliminarse una vez que se solucione este error, ya que su idoneidad NO se ha probado con versiones fijas.

Usa esta subclase de JTable.

Nota: Esto es para MetalLookAndFeel. Si se usan otras apariencias, la subclase FixedTableUI interna tendrá que extender la subclase TableUI para esa apariencia.

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);
      }
  }
}

Nota Consulte la página http://bugs.sun.com

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top