Сохранять выбор JTable для изменения TableModel
Мы видим, что выбор JTable
очищается, когда мы делаем fireTableDataChanged()
или fireTableRowsUpdated()
из TableModel
.
Ожидается ли это, или мы делаем что-то неправильно? Я не видел никакого свойства в JTable
(или других связанных классах) об очистке/сохранении выбора в обновлениях модели.
Если это поведение по умолчанию, есть ли хороший способ предотвратить это? Может быть, какой-то способ "заблокировать" выбор перед обновлением и разблокировать после?
Разработчик экспериментировал с сохранением выбора перед обновлением и повторным применением. Это немного медленно.
Это Java 1.4.2 в Windows XP, если это имеет значение. Мы ограничены этой версией, основанной на некотором коде поставщика, который мы используем.
Ответы
Ответ 1
Вам нужно сохранить выделение, а затем повторно применить его.
Прежде всего вам нужно будет получить список всех выбранных ячеек.
Затем, когда вы повторно загружаете JTable с новыми данными, вам необходимо программно повторно применить те же самые параметры.
Другая точка, которую я хочу сделать, - если число или строки или столбцы в таблице увеличиваются или уменьшаются после перезагрузки каждой таблицы, то, пожалуйста, не беспокойтесь о сохранении выбора.
Пользователь мог выбрать столбец 1-й строки 1, имеющий значение "Утка", до обновления модели. Но после обновления модели, что те же самые данные теперь могут встречаться в столбце 1 строки 4, а ваш исходный столбец строки 2 строки 1 может иметь новые данные, такие как "Свинья". Теперь, если вы принудительно установите выделение в соответствии с тем, что было до обновления модели, это может быть не то, что нужно пользователю.
Таким образом, программный выбор ячеек может быть обоюдоострым мечом. Не делайте этого, если вы не уверены.
Ответ 2
Вы можете автоматически сохранить выбор таблицы, если СТРУКТУРА этой таблицы не изменилась (т.е. если вы не добавляли/не удаляли какие-либо столбцы/строки) следующим образом.
Если вы написали свою собственную реализацию 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, последний из которых действует как означающий, который не только имеет все данные в таблице изменились, но число строк также может иметь.
Ответ 3
Это поведение по умолчанию. Если вы вызываете fireTableDataChanged()
, вся таблица перестраивается с нуля, когда вы устанавливаете совершенно новую модель. В этом случае выбор, естественно, теряется. Если вы вызываете fireTableRowsUpdated()
, выбор также очищается в общих случаях. Единственный способ - запомнить выбор, а затем установить это. К сожалению, нет никакой гарантии, что выбор будет по-прежнему действительным. Будьте осторожны при восстановлении выбора.
Ответ 4
для справки, как заявил @Swapnonil Mukherjee, это сделал трюк со столом с выбираемыми строками:
// preserve selection calling fireTableDataChanged()
final int[] sel = table.getSelectedRows();
fireTableDataChanged();
for (int i=0; i<sel.length; i++)
table.getSelectionModel().addSelectionInterval(sel[i], sel[i]);
Ответ 5
Если я правильно помню, сохранение выбора и повторное применение этого - это то, что мы тоже сделали...
Ответ 6
У меня была такая же проблема в приложении. В моем случае модель в таблице была списком объектов, где свойства объекта, сопоставленные столбцам. В этом случае, когда список был изменен, я получил выбранный индекс и сохранил объект, который был выбран до обновления списка. После того, как список будет изменен и до обновления таблицы, я бы вычислил позицию выбранного объекта. Если он все еще присутствует после модификации, я бы установил выделение в новый индекс.
Просто установите выделенный индекс в таблице после того, как модификация не будет работать, поскольку объект может изменить позицию в списке.
В качестве примечания я обнаружил, что работа с GlazedLists значительно облегчает жизнь при работе с таблицами.
Ответ 7
Я столкнулся с той же проблемой, и когда я попытался найти причину, у меня возник этот вопрос, но это похоже на ошибку в Java SDK. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786
WORK AROUND
Доступен временной обход. Он должен быть удален после исправления этой ошибки, поскольку ее пригодность НЕ тестировалась в отношении фиксированных выпусков.
Используйте этот подкласс 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 to http://bugs.sun.com