Удаление строк из DefaultTableModel с присоединенным RowSorter не удаляет последнюю строку

Я новичок в Java, особенно в таблицах, и у меня возникают проблемы с одной конкретной задачей.

У меня есть JTable, в котором используется настраиваемая модель таблицы, расширяющая DefaultTableModel, и я прикрепил к таблице TableRowSorter. В приведенном ниже примере приложения есть две кнопки: одна загружает строки в таблицу, а другая удаляет все выбранные строки из таблицы.

По какой-то причине, если вы выберете последнюю строку в таблице вместе с любой другой строкой, когда вы нажмете кнопку «Удалить», она удалит все выбранные строки, кроме последней. Вы можете удалить любую другую комбинацию строк, и она отлично работает.

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

Чтобы увидеть поведение, нажмите кнопку «Загрузить», чтобы заполнить таблицу, выберите все строки в таблице, затем нажмите кнопку «Удалить». Он удалит все строки, кроме последней.

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

Я использую версию Java 1.6.0_16. Есть идеи относительно того, что я делаю неправильно?

Спасибо,

Джо

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.util.Arrays;

public class TableTest
extends JFrame
{
  private JTable widgetTable;
  private WidgetTableModel widgetTableModel;

  public static void main(String[] args)
  {
    TableTest frame = new TableTest();
    frame.setSize(600, 400);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public TableTest()
  {
    this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    EventQueue.invokeLater(new Runnable() { public void run() { createUI(); } });
  }

  private void createUI()
  {
    this.setLayout(new BorderLayout());

    JButton loadButton = new JButton("Load");
    loadButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        loadPerformed();
      }
    });

    this.add(loadButton, BorderLayout.NORTH);

    widgetTableModel = new WidgetTableModel();
    widgetTable = new JTable(widgetTableModel);
    widgetTable.setRowSorter(new TableRowSorter<WidgetTableModel>(widgetTableModel));
    this.add(new JScrollPane(widgetTable), BorderLayout.CENTER);

    JButton removeButton = new JButton("Remove");
    removeButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        removePerformed();
      }
    });

    this.add(removeButton, BorderLayout.SOUTH);
  }

  private void loadPerformed()
  {
    widgetTableModel.addRow(new Object[] {"Widget 1"});
    widgetTableModel.addRow(new Object[] {"Widget 2"});
    widgetTableModel.addRow(new Object[] {"Widget 3"});
    widgetTableModel.addRow(new Object[] {"Widget 4"});
    widgetTableModel.addRow(new Object[] {"Widget 5"});
  }

  private void removePerformed()
  {
    int selectedRow = widgetTable.getSelectedRow();

    while (selectedRow >= 0) {
      System.out.println("selectedRowCount=" + widgetTable.getSelectedRowCount());
      int modelRow = widgetTable.convertRowIndexToModel(selectedRow);
      widgetTableModel.removeRow(modelRow);
      selectedRow = widgetTable.getSelectedRow();
    }
  }
}


class WidgetTableModel
extends DefaultTableModel
{
  public WidgetTableModel()
  {
    this.addColumn("Column 1");
  }
}

person Community    schedule 20.10.2009    source источник


Ответы (2)


Измените «пока» на «если». Выделите все строки и нажмите кнопку. По какой-то причине последняя строка теряет выделение. Не знаю почему.

Я считаю, что логику удаления обычно следует выполнять с последней строки до 0. Таким образом, вам не нужно беспокоиться об изменении значений индекса строки при удалении строки. Поэтому вам нужно использовать метод getSelectedRows () и перебирать массив в обратном порядке. Хотя, должен признать, я никогда не делал этого на отсортированной таблице, поэтому я не уверен, вызовет ли это проблему или нет.

person camickr    schedule 20.10.2009
comment
Перебор выбранных строк в обратном порядке должен работать, но это кажется ненужным. То, как работает пример сейчас, должно быть таким же надежным - всегда получать первую выбранную строку в таблице. Это также избавляет от необходимости отслеживать изменения индекса. Проблема, по-видимому, заключается в ошибке (или в любом другом источнике), которая приводит к отмене выбора этой последней строки. - person ; 22.10.2009

Обсуждается также на java.net: http://www.java.net/node/698236

Это ошибка №6894632 в основном DefaultRowSorter: в ее основе (как описано в отчет) - это не очень хорошо определенная семантика getModelRowCount (). Это исправлено в SwingX DefaultSortController.

/** 
 * Additionally, this implementation contains a fix for core 
 * <a href=http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6894632>Issue 6894632</a>.
 * It guarantees to only touch the underlying model during sort/filter and during 
 * processing the notification methods. This implies that the conversion and size query
 * methods are valid at all times outside the internal updates, including the critical 
 * period (in core with undefined behaviour) after the underlying model has changed and 
 * before this sorter has been notified.
 */

К сожалению, ветка на форуме SwingLabs, содержащая полный анализ (была: http://www.java.net/jive/thread.jspa?threadID=77343) больше не доступен после переноса проекта ...

person kleopatra    schedule 14.12.2011