保持对TableModel更改的JTable选择

当我们从TableModel执行fireTableDataChanged()fireTableRowsUpdated()时,我们看到JTable选择被清除。

这是预期的,还是我们做错了什么? 我没有在JTable (或其他相关类)上看到关于清除/保留模型更新选择的任何属性。

如果这是默认行为,是否有一种防止这种情况的好方法? 也许某种方式在更新之前“锁定”选择并在之后解锁?

开发人员一直在尝试在更新之前保存选择并重新应用它。 这有点慢。

这是Windows XP上的Java 1.4.2,如果这很重要的话。 我们仅限于基于我们使用的某些供应商代码的版本。

您需要保留选择,然后重新应用它。

首先,您需要获取所有选定单元格的列表。

然后,当您使用新数据重新加载JTable时,需要以编程方式重新应用这些相同的选择。

我要做的另一点是,如果表格中的数字或行数或列数在每个表格模型重新加载后增加或减少,那么请不要打扰保留选择。

在模型更新之前,用户可以选择具有值“Duck”的第2行第1列。 但是在模型更新之后,相同的数据现在可以在第4行第1列中出现,并且您的原始单元格第2列第1列可能具有新数据,例如“Pig”。 现在,如果您强制将选择设置为模型更新之前的选择,则可能不是用户想要的。

因此,以编程方式选择单元格可能是一把双刃剑。 如果你不确定,不要这样做。

如果该表的STRUCTURE没有更改(即,如果您没有添加/删除任何列/行),则可以自动保留表的选择,如下所示。

如果您编写了自己的TableModel实现,则可以简单地覆盖fireTableDataChanged()方法:

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

如果只有数据而不是表的结构发生了变化,这应确保维持您的选择。 它之间的唯一区别是,如果不重写此方法将会调用的是getRowCount() – 1为lastRow参数而不是Integer.MAX_VALUE传递,后者的作用是一个不仅具有所有表中的数据已更改,但行数也可能已更改。

这是默认行为。 如果调用fireTableDataChanged() ,则在设置全新模型时将从头开始重建整个表。 在这种情况下,选择自然会丢失。 如果调用fireTableRowsUpdated() ,则通常情况下也会清除选择。 唯一的方法是记住选择,然后设置它。 遗憾的是,无法保证选择仍然有效。 恢复选择时要小心。

作为参考,正如@Swapnonil Mukherjee所说,这可以通过一个带有可选行的表来实现:

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

如果我没记错的话,保存选择并重新应用它也是我们所做的……

我在应用程序中遇到了同样的问题。 在我的例子中,表中的模型是一个对象列表,其中对象属性映射到列。 在这种情况下,当列表被修改时,我检索了所选索引并存储了在更新列表之前选择的对象。 修改列表后,在更新表之前,我将计算所选对象的位置。 如果修改后它仍然存在,那么我会将选择设置为新索引。

只是在修改后在表中设置选定的索引将不起作用,因为该对象可能会更改列表中的位置。

作为旁注,我发现使用GlazedLists可以在处理表格时更轻松。

我遇到了同样的问题,当我试图搜索我得到这个问题的原因但它似乎是Java SDK中的一个错误。 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

周围的工作

可以进行临时解决方案。 一旦修复了这个bug就应该删除它,因为它的适用性没有针对固定版本进行测试。

使用JTable的这个子类。

注意:这适用于MetalLookAndFeel。 如果使用其他外观,内部FixedTableUI子类将必须扩展TableUI子类以获得该外观。

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

请注意 Curtsey到http://bugs.sun.com