【发布时间】:2012-03-29 20:20:00
【问题描述】:
在我的 JTable 中,我已经在更新期间实现了选择保留逻辑。不幸的是,我想我遇到了某种错误。 JTable 由后台线程更新,该线程获取新数据并从表模型中添加/修改/删除它。
只有在用户拖动鼠标选择表格中的行时执行更新时才会出现问题。最让我困惑的是:
- 如果我从一行开始并向上移动鼠标以选择前面的行,一切都会完美运行:选择会在更新中保留,并且用户操作会继续正确
- 如果我从一行开始并向下 移动鼠标以选择以下行,它会中断:当更新触发时,当前选择丢失,新选择从当前行开始更新触发时指针下方。
任何线索说明为什么会发生这种情况?
这是我正在谈论的代码的精简版本。
我正在使用手动同步的TreeSet 来更新后台线程中的数据(请参阅update)。完成后,我调用atomicSwapData 创建将由getValueAt 使用的数组。
在 updateTable 中,您可以看到我是如何实现我之前谈到的选择保留逻辑的。如您所见,我尝试使用EventQueue.invokeLater 方法,但问题仍然出现。请注意,所有方法都可以被任何线程调用,而不仅仅是 EDT。
class MyDataModel extends AbstractTableModel {
TreeSet<MyDataItem> ht = new TreeSet<MyDataItem>();
MyDataItem[] _ht = MyDataItem.emptyArray();
public Object getValueAt(int row, int col) {
MyDataItem qdi;
synchronized (_ht) {
qdi = _ht[row];
}
// return one of the members of qdi, based on col
}
public void update(String qm, Collection<MyDataItem> toAdd) {
HashSet<MyDataItem> toDrop = new HashSet<MyDataItem>();
synchronized (ht) {
// do something with ht
}
swapData();
}
private void swapData() {
EventQueue.invokeLater(new Runnable() {
public void run() {
synchronized(_ht) {
MyDataItem[] tmp = ht.toArray(MyDataItem.emptyArray());
synchronized(tmp) {
_ht = tmp;
}
}
}
});
updateTable();
}
private void updateTable() {
EventQueue.invokeLater(new Runnable() {
public void run() {
synchronized (_ht) {
int[] rowIndices = table.getSelectedRows();
fireTableDataChanged();
for (int row: rowIndices)
table.addRowSelectionInterval(row, row);
}
}
});
}
}
【问题讨论】:
-
你是说你在另一个线程上更新
TableModel然后是 EDT。首先修复它(例如,使用SwingWorker在后台线程上获取新数据,但在新数据可用后更新 EDT 上的TableModel) -
按照您描述的方式实现它可能更简洁,但我通过使用对 TableModel 中保存数据的对象的同步访问来解决它。
-
请用SSCCE编辑你的问题,没办法:-)
-
在更新过程中已经实现了选择保留逻辑听起来很可疑:通常表自己会这样做,不需要做任何特别的事情。我的猜测是不正确的更新通知 - 当然,在你显示 SSCCE 之前,什么都没有 :-)
-
@CAFxX 此代码与 AbstractTableModel 无关,我错过了基于此模型创建、保存、修改 JTable 的所有重要方法
标签: java swing jtable mouseevent