Java 在表格模型更改中保留JTable选择
当我们从Java 在表格模型更改中保留JTable选择,java,swing,jtable,tablemodel,Java,Swing,Jtable,Tablemodel,当我们从TableModel执行fireTableDataChanged()或fireTableRowsUpdated()时,我们看到JTable选择被清除 这是意料之中的事,还是我们做错了什么?我在JTable(或其他相关类)上没有看到关于清除/保留模型更新选择的任何属性 如果这是默认行为,有没有好的方法来防止?也许可以在更新前“锁定”选择,然后在更新后解锁 开发人员一直在尝试在更新之前保存选择并重新应用它。有点慢 这是WindowsXP上的Java1.4.2,如果这很重要的话。根据我们使用的
TableModel
执行fireTableDataChanged()
或fireTableRowsUpdated()
时,我们看到JTable
选择被清除
这是意料之中的事,还是我们做错了什么?我在JTable
(或其他相关类)上没有看到关于清除/保留模型更新选择的任何属性
如果这是默认行为,有没有好的方法来防止?也许可以在更新前“锁定”选择,然后在更新后解锁
开发人员一直在尝试在更新之前保存选择并重新应用它。有点慢
这是WindowsXP上的Java1.4.2,如果这很重要的话。根据我们使用的某些供应商代码,我们仅限于该版本。如果我没记错的话,保存选择并重新应用它也是我们所做的…您需要保留选择,然后重新应用它 首先,您需要获得所有选定单元格的列表 然后,当您用新数据重新加载JTable时,您需要以编程方式重新应用这些相同的选择 我想指出的另一点是,如果在每次重新加载表模型后,表中的行数或列数增加或减少,那么请不要费心保留选择 在模型更新之前,用户可以选择第2行第1列,其值为“Duck”。但在模型更新之后,相同的数据现在可以出现在第4行第1列中,而您的原始单元格第2行第1列可能会有新的数据,例如“Pig”。现在,如果强制将选择设置为模型更新之前的状态,这可能不是用户想要的
因此,以编程方式选择单元格可能是一把双刃剑。如果你不确定,就不要这样做 这是默认行为。如果调用
fireTableDataChanged()
,则在设置全新模型时,整个表将从头开始重建。在这种情况下,选择自然会丢失。如果调用fireTableRowsUpdated()
,则在一般情况下也会清除该选项。唯一的方法是记住所选内容,然后设置此选项。不幸的是,无法保证选择仍然有效。如果要恢复选择,请小心 我在一个应用程序中遇到了同样的问题。在我的例子中,表中的模型是一个对象列表,其中对象属性映射到列。在这种情况下,当修改列表时,我检索所选索引并存储更新列表之前所选的对象。修改列表后,在更新表之前,我将计算选定对象的位置。如果修改后它仍然存在,那么我会将选择设置为新索引
修改后仅在表中设置所选索引将不起作用,因为对象可能会更改列表中的位置
作为补充说明,我发现使用GlazedList可以使处理表时的工作更加轻松。如果表的结构没有改变(即,如果没有添加/删除任何列/行),则可以自动保留该表的选择,如下所示 如果您已经编写了自己的TableModel实现,只需重写fireTableDataChanged()方法即可:
@覆盖
public void fireTableDataChanged(){
fireTableChanged(新TableModelEvent(此,//tableModel
0,//第一行
getRowCount()-1,//最后一行
TableModelEvent.ALL_列,//列
TableModelEvent.UPDATE));//变更类型
}
这将确保您的选择得到维护,前提是只有数据而不是表的结构发生了更改。这与如果不重写此方法将调用的唯一区别是,为lastRow参数传递getRowCount()-1,而不是Integer.MAX_值,后者充当一个符号,不仅改变了表中的所有数据,而且行数也可能改变 我也面临着同样的问题,当我试图搜索得到这个问题的原因时,它似乎是Java SDK中的一个bug 变通 可提供临时工作环境。一旦修复了这个bug,就应该删除它,因为它的适用性还没有针对固定版本进行测试 使用JTable的这个子类 注意:这是为金属手感设计的。如果使用其他外观,内部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);
}
}
}
注意向行屈膝礼作为参考,正如@Swapnonil Mukherjee所说的,这在一张有可选择行的桌子上起到了作用:
//保留调用fireTableDataChanged()的选择
final int[]sel=table.getSelectedRows();
fireTableDataChanged();
对于(int i=0;iWare:这样做可能适得其反-更改的数据可能包括插入/删除。如果是这种情况,侦听器可能会受到严重误导,那么这不是结构更改吗?不,结构更改是指列随数据一起更改,您指的是列和/或行,对吗?插入/删除是指添加列吗ns和/或行或其他什么?抱歉,我想我还是有点困惑,但听起来你在这里说的对我来说非常重要。是的,触发哪个事件的api文档并不太清楚:要理解,我们必须仔细阅读AbstractTableModel.fireXX方法和TableModelEvent;-)tableModel的结构==一组列,因此无论何时删除/插入(或甚至移动)列,都必须触发structureChanged。单边界范围的插入/删除/更新是显而易见的。包含难以表达(以单块表示)的插入/删除的更改必须触发dataChanged