【问题标题】:Selection lost with mouse drag and concurrent update in JTableJTable 中的鼠标拖动和并发更新导致选择丢失
【发布时间】: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


【解决方案1】:

作为参考,此example 使用EventQueue.invokeLater() 从后台线程不断更新TableModel。它没有表现出你描述的异常。

【讨论】:

  • 查看更新后的问题。使用 invokeLater 似乎并不能解决问题。
  • 是的,在 EDT 上更新 TableModel 是必要条件,但不是充分条件。你需要wrap你的集合吗?
  • synchronized(ht) { ... } 还不够用吗?
【解决方案2】:

jtable 的标准绘制是从上到下的,这可能是它在一个方向而不是另一个方向中断的原因。

你必须更加清楚并定义你的“休息”

它只是把选择画错了吗?那么你应该能够通过在更新触发后强制你的表进行完全重绘来修复它

【讨论】:

  • 你能解释一下“定义你的'休息'”是什么意思吗?
  • 另外,这不仅仅是绘画错误。选择本身已更改。
  • 我的意思是定义你的休息时间:清楚地解释你认为“休息”是什么,更具体地说明到底出了什么问题。
猜你喜欢
  • 1970-01-01
  • 2017-05-27
  • 1970-01-01
  • 1970-01-01
  • 2015-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多