После добавления TableRowSorter добавление значений в модель вызывает java.lang.IndexOutOfBoundsException: неверный диапазон

После добавления TableRowSorter в таблицу и соответствующую модель любое соответствующее добавление специально для firetabletablerowsinserted вызывает исключения. Из тестирования ясно, что GetRowCount() возвращает значение за пределами диапазона моделей. Однако для меня не имеет смысла, как продолжать добавлять значения в таблицу после добавления сортировщика или фильтра?

В качестве примера я устанавливаю фильтр строк перед добавлением чего-либо в таблицу, а затем добавляю значение в таблицу со следующими вызовами в моей модели:

this.addRow(row, createRow(trans,row));
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());

Количество строк имеет размер 1, и возникает исключение:

java.lang.IndexOutOfBoundsException: Invalid range
at javax.swing.DefaultRowSorter.checkAgainstModel(Unknown Source)
at javax.swing.DefaultRowSorter.rowsInserted(Unknown Source)
at com.gui.model

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

this.addRow(row, createRow(trans,row));
this.fireTableStructureChanged()
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());

Я даже пытался уведомить сортировщик внутри модели о том, что в модель было добавлено значение перед вызовом огня, как показано ниже, но это также не удалось:

 this.addRow(row, createRow(trans,row));
 if(sorter.getRowFilter() != null){
      //if a sorter exists we are in add notify sorter
      sorter.rowsInserted(getRowCount(), getRowCount());
  }
  this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());

Наконец, я жестко закодировал FireTableRowsInsterted(0,0), и он не выдает никаких исключений. Но ничего не добавляется в таблицу? Итак, я знаю, что это определенно какая-то проблема OutOfBounds. Я просмотрел все и не могу найти ответ. Если кто-нибудь знает, как это должно работать, это будет очень полезно. Вот код, который устанавливает сортировщик внутри jpanel:

    messageTable.setRowSorter(null);
     HttpTransactionTableModel m = getTransactionTableModel();
     final int statusIndex = m.getColIndex("status");
     RowFilter<Object,Object> startsWithAFilter = new RowFilter<Object,Object>() {
           public boolean include(Entry<? extends Object, ? extends Object> entry) {

               for(char responseCode:responseCodes)
               {
                   if (entry.getStringValue(statusIndex).startsWith(Character.toString(responseCode))) {
                         return true;
                       }
               }


             // None of the columns start with "a"; return false so that this
             // entry is not shown
             return false;
           }
         };


        m.sorter.setRowFilter(startsWithAFilter);
        messageTable.setRowSorter(m.sorter);

Вот код внутри моей модели, который добавляет ценность модели:

public void update(Observable o, Object evt) {
    if (evt instanceof ObservableEvent<?>) {

        ObservableEvent<?> event = (ObservableEvent<?>) evt;

        if (event.getElement() instanceof HttpTransaction) {

            HttpTransaction trans = (HttpTransaction) event.getElement();

            // handle adding of an element
            if (event.getAction() == PUT) {

                if (includeTransaction(trans)) {

                    // handle request elements
                    if (trans.getRequest() != null && idMap.get(trans.getID()) == null) {

                        idMap.put(trans.getID(), count++);
                       // transactionManager.save(trans);
                        int row = idMap.get(trans.getID());
                        this.addRow(row, createRow(trans,row));
                        if(sorter.getRowFilter() != null){
                            sorter.rowsInserted(getRowCount(), getRowCount());
                        }
                        this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());

                    }

person steve    schedule 28.05.2011    source источник
comment
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount()); -- меньше на единицу, это индекс с отсчетом от нуля   -  person Whired    schedule 04.06.2012
comment
+1 @Whired - хороший споттинг :-)   -  person kleopatra    schedule 17.08.2012


Ответы (3)


У вас аут на 1 ошибку. Правильный код запуска события:

this.fireTableRowsInserted(this.getRowCount()-1, this.getRowCount()-1);
person Paul    schedule 03.06.2011
comment
рассмотрите возможность редактирования своего ответа: ошибка, которую вы нашли в своем коде, такая же, как основная ошибка в коде OP :-) - person kleopatra; 17.08.2012
comment
@kleopatra, хорошее предложение, я отредактировал свой ответ, так что это просто ответ. - person Paul; 10.05.2013

Я вернулся и лучше посмотрел на это, увидев комментарий Клеопатры. Я менял свою TableModel после создания RowSorter, но до присоединения RowSorter к JTable. Вот пример, который показывает проблему, с которой я столкнулся.

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
import java.util.ArrayList;
import java.util.List;

public class TestTableMain {
    public static void main(String[] args) {
        new TestTableMain();
    }

    public TestTableMain() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                buildAndShowMainFrame();
            }
        });
    }

    private void buildAndShowMainFrame() {
        JFrame frame = new JFrame();
        JScrollPane scrollPane = new JScrollPane();

        TestTableModel model = new TestTableModel();
        JTable table = new JTable(model);

        TableRowSorter<TestTableModel> rowSorter = new TableRowSorter<>(model);
        rowSorter.setRowFilter(null);

        model.add("First added item.");
        /* The RowSorter doesn't observe the TableModel directly. Instead,
         * the JTable observes the TableModel and notifies the RowSorter
         * about changes. At this point, the RowSorter(s) internal variable
         * modelRowCount is incorrect.  There are two easy ways to fix this:
         *
         * 1. Don't add data to the model until the RowSorter has been
         * attached to the JTable.
         *
         * 2. Notify the RowSorter about model changes just prior to
         * attaching it to the JTable.
         */

        // Uncomment the next line to notify rowSorter that you've changed
        // the model it's using prior to attaching it to the table.
        //rowSorter.modelStructureChanged();
        table.setRowSorter(rowSorter);

        scrollPane.setViewportView(table);
        frame.setContentPane(scrollPane);

        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);

        model.add("Second added item.");
    }

    private class TestTableModel extends AbstractTableModel {
        private List<String> items = new ArrayList<>();

        public TestTableModel() {
            for(int i=0;i<5;i++) {
                add("Item " + i);
            }
        }

        @Override
        public int getRowCount() {
            return items.size();
        }

        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return items.get(rowIndex);
        }

        public void add(String item) {
            items.add(item);
            fireTableRowsInserted(items.size() - 1, items.size() - 1);
        }
    }
}
person Ryan J    schedule 16.08.2012
comment
просто неправильно - никогда не пытайтесь угадать нормальное внутреннее обновление. Вместо этого попробуйте найти ошибку в своем коде, а не добавлять что-то случайным образом ;-) - person kleopatra; 17.08.2012
comment
@kleopatra Ты прав. Сегодня я выследил настоящую причину и обновил свой ответ. - person Ryan J; 18.08.2012
comment
вы можете рассмотреть возможность удаления оригинальной части - неправильные вещи имеют тенденцию оставаться в памяти :-) - person kleopatra; 18.08.2012
comment
Я все еще в замешательстве даже после этого ответа. Когда я запускаю ваш код, он выдает ошибку. Когда я раскомментирую строку modelStructureChanged(), она работает. Но мы согласились (да, в javadocs конкретно сказано), что неправильно вызывать этот метод самостоятельно. Так что тут на вынос?? - person ryvantage; 12.07.2018
comment
1. Не добавляйте данные в модель, пока RowSorter не будет присоединен к JTable. В моем коде RowSorter добавляется в таблицу до вызова метода addRow, и я все еще получаю сообщение об ошибке. Так что я не думаю, что это имеет значение. - person ryvantage; 12.07.2018
comment
@ryvantage Я только что запустил его, и присоединение RowSorter перед изменением модели у меня работает. Я думаю, что это лучший подход, если это возможно. В моем примере переместите table.setRowSorter(rowSorter) выше model.add("First added item."). JavaDocs говорят You normally do not call this method. Я не думаю, что это означает, что это запрещено, просто это обычно не делается. Этот вопрос довольно старый, и я никогда не принимал ответа, потому что ни один из них не очень хорошо объясняет решение. Возможно, вы захотите начать новый вопрос с кода, который вызывает у вас проблемы. - person Ryan J; 13.07.2018

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

                         if(sorter.getRowFilter() != null){
                             sorter.modelStructureChanged();
                           }
                           else
                         this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());
person steve    schedule 29.05.2011
comment
просто неправильно - см. комментарий в комментарии @Paul к его собственному ответу: та же ошибка в вашем. Кстати, никогда не запускайте событие модели из вне модели. Уведомление заинтересованных сторон является исключительной ответственностью модели ... - person kleopatra; 17.08.2012