В моем 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);
}
}
});
}
}