Сохранить выбор JTable при изменении TableModel - PullRequest
15 голосов
/ 31 октября 2008

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

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

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

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

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

Ответы [ 7 ]

4 голосов
/ 20 марта 2012

Вы можете автоматически сохранить выбор таблицы, если СТРУКТУРА этой таблицы не изменилась (то есть, если вы не добавили / не удалили столбцы / строки) следующим образом.

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

4 голосов
/ 01 ноября 2008

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

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

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

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

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

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

1 голос
/ 25 августа 2015

для справки, как сказал @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]);
1 голос
/ 07 ноября 2008

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

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

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

1 голос
/ 02 ноября 2008

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

0 голосов
/ 09 августа 2013

Я столкнулся с той же проблемой, и когда попытался найти причину, я получил этот вопрос, но, похоже, ошибка в 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

0 голосов
/ 31 октября 2008

Если я правильно помню, мы сохранили выделение и повторно применили его ...

...