Сохранять выбор 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