After adding a TableRowSorter adding values to model cause java.lang.IndexOutOfBoundsException: Invalid range

人走茶凉 提交于 2019-12-03 11:50:44

You have an out by 1 error. The correct code for firing the event is:

this.fireTableRowsInserted(this.getRowCount()-1, this.getRowCount()-1);

I went back and had a better look at this after seeing kleopatra's comment. I was changing my TableModel after creating a RowSorter, but before attaching the RowSorter to the JTable. Here's an example that shows the problem I was having.

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);
        }
    }
}

So, for now it looks like if you check in your model if your currently in sorting mode and if that is case only call update on sorting model. Otherwise call normal model fire updates everything seems to work so far. I'm still open for better ways to handle this though:

                         if(sorter.getRowFilter() != null){
                             sorter.modelStructureChanged();
                           }
                           else
                         this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!