Сохранить выбор JTable для изменения TableModel

мы видим JTable выбор очищается, когда мы делаем fireTableDataChanged() или fireTableRowsUpdated() С TableModel.

это нормально, или мы делаем что-то неправильно? Я не видел никакой собственности на JTable (или другие связанные классы) об очистке/сохранении выбора в обновлениях модели.

если это поведение по умолчанию, есть ли хороший способ предотвратить это? Может быть какой-то способ "блокировки" выбора до обновления и после?

разработчик экспериментировал с сохранением выбора Перед обновлением и повторным его применением. Это немного медленно.

это Java 1.4.2 в Windows XP, если это имеет значение. Мы ограничены этой версией на основе кода поставщика, который мы используем.

7 ответов


вы должны сохранить выделение, а затем повторно применить его.

прежде всего вам нужно будет получить список всех выбранных ячеек.

затем, когда вы повторно загружаете JTable с новыми данными, вам нужно программно повторно применить те же самые выборы.

другой момент, который я хочу сделать, это, если число или строки или столбцы в вашей таблице увеличиваются или уменьшаются после каждой перезагрузки модели таблицы, то, пожалуйста, не беспокойтесь о сохранении выбора.

пользователь мог выбрать столбец строки 2 1 со значением "утка" перед обновлением модели. Но после обновления модели те же данные теперь могут встречаться в столбце 1 строки 4, а ваша исходная строка ячейки 2 столбца 1 может иметь новые данные, такие как "свинья". Теперь, если вы принудительно установите выбор на то, что было до обновления модели, это может быть не то, что хотел пользователь.

таким образом, программный выбор ячеек может быть обоюдоострым мечом. Не делайте этого, если вы не уверены.


вы можете автоматически сохранить выбор таблицы, если структура этой таблицы не изменилась (т. е. если вы не добавили/удалили какие-либо столбцы/строки) следующим образом.

Если вы написали свою собственную реализацию 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, последний из которых действует как означающее, которое не только изменило все данные в таблице, но и количество строк.


это поведение по умолчанию. Если вы позвоните fireTableDataChanged() вся таблица перестраивается с нуля, когда вы устанавливаете совершенно новую модель. В этом случае отбор, естественно, теряется. Если вы позвоните fireTableRowsUpdated() выбор также очищается в общих случаях. Единственный способ-запомнить выбор, а затем установить это. К сожалению, нет никакой гарантии, что выбор будет по-прежнему действует. Будьте осторожны при восстановлении выделения.


для справки, как заявил @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]);

Если я правильно помню, сохранение выбора и повторное применение-это то, что мы тоже сделали...


У меня была такая же проблема в приложении. В моем случае модель в таблице была списком объектов, где свойства объекта сопоставлялись столбцам. В этом случае, когда список был изменен, я извлек выбранный индекс и сохранил объект, который был выбран перед обновлением списка. После изменения списка и до обновления таблицы я бы рассчитал положение выбранного объекта. Если бы он все еще присутствовал после модификации, я бы установил выбор к новому индексу.

просто установка выбранного индекса в таблице после изменения не будет работать, потому что объект может изменить положение в списке.

в качестве примечания я обнаружил, что работа с GlazedLists делает жизнь намного проще при работе с таблицами.


я столкнулся с той же проблемой, и когда попытался найти причину, по которой я получил этот вопрос, но это кажется ошибкой в Java SDK. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

ОБОЙТИ

доступен временный обходной путь. Он должен быть удален после исправления этой ошибки, поскольку ее пригодность не была протестирована против фиксированных выпусков.

используйте этот подкласс 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);
      }
  }
}

Примечание реверансы в сторону http://bugs.sun.com