【问题标题】:After adding a TableRowSorter adding values to model cause java.lang.IndexOutOfBoundsException: Invalid range添加 TableRowSorter 后向模型添加值导致 java.lang.IndexOutOfBoundsException: Invalid range
【发布时间】:2011-05-28 23:43:33
【问题描述】:

将 TableRowSorter 添加到表及其对应模型后,任何相应的添加都专门在 firetabletablerowsinserted 导致异常。从测试中可以清楚地看出 GetRowCount() 正在返回一个超出模型范围的值。但是,在添加排序器或过滤器后如何继续向表中添加值对我来说没有意义?

例如,我在向表中添加任何内容之前设置行过滤器,然后在我的模型中使用以下调用向表中添加一个值:

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

rowcount 大小为 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());

我什至尝试在调用 fire 之前通知模型内部的排序器一个值已添加到模型中,如下所示,但它也失败了:

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

                    }

【问题讨论】:

  • this.fireTableRowsInserted(this.getRowCount(), this.getRowCount()); -- 减一,它是从零开始的索引
  • +1 @Whired - 很好的发现:-)

标签: swing jtable tablerowsorter


【解决方案1】:

您有 1 个错误。触发事件的正确代码是:

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

【讨论】:

  • 考虑编辑您的答案:您在代码中发现的错误与 OPs 代码中的潜在错误相同 :-)
  • @kleopatra,好建议,我已经编辑了我的答案,所以这就是答案。
【解决方案2】:

在看到 kleopatra 的评论后,我回去更好地了解了这一点。在创建 RowSorter 之后,但在将 RowSorter 附加到 JTable 之前,我正在更改我的 TableModel。这是一个显示我遇到的问题的示例。

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

【讨论】:

  • 完全错了 - 永远不要尝试第二次猜测正常的内部更新。相反,尝试在代码中查找错误,而不是随机添加内容;-)
  • @kleopatra 你是对的。我今天找到了真正的原因,并更新了我的答案。
  • 您可能会考虑删除原始部分 - 错误的东西往往会记住:-)
  • 即使得到了这个答案,我仍然很困惑。当我运行您的代码时,它会引发错误。当我取消注释 modelStructureChanged() 行时,它可以工作。但是我们同意(不,javadocs 特别说)自己调用该方法是错误的。那么这里的要点是什么??
  • "1. 在将 RowSorter 附加到 JTable 之前,不要将数据添加到模型中。"在我的代码中,RowSorter 在调用 addRow 方法之前被添加到表中,但我仍然得到错误。所以我不认为这有什么不同。
【解决方案3】:

所以,现在看来,如果您检查您的模型,如果您当前处于排序模式,并且如果是这种情况,则仅调用排序模型的更新。否则调用正常模型火灾更新到目前为止一切似乎都有效。不过,我仍然愿意寻找更好的方法来处理这个问题:

                         if(sorter.getRowFilter() != null){
                             sorter.modelStructureChanged();
                           }
                           else
                         this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());

【讨论】:

  • 完全错了 - 请参阅@Paul 对他自己的回答的评论中的评论:你的错误相同。顺便说一句,永远不会从模型的外部触发模型事件。通知相关方是模型的专属责任......
猜你喜欢
  • 1970-01-01
  • 2015-03-23
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多