Сохранение выбора JTable при изменении табличной модели

StackOverflow https://stackoverflow.com/questions/254212

  •  05-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

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

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

Пользователь мог выбрать строку 2 столбца 1 со значением скажем "Duck" до обновления модели. Но после обновления модели эти же данные теперь могут появиться в столбце 1 строки 4, а в исходном столбце 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, последний из которых действует как указатель, который не только имеет все данные в таблице изменились, но количество строк также может быть.

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

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

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

Это поведение по умолчанию. Если вы вызываете 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]);

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

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

ОБХОДИТЕ СТОРОНОЙ

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

Используйте этот подкласс JTable.

Примечание:Это для восприятия металла.Если используется другой внешний вид, внутреннему подклассу 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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top