插入行后的IndexOutOfBoundsException,表排序,然后行删除

时间:2018-05-08 20:44:00

标签: java swing

在之前的一个问题(Convert modelRowIndex to viewRowIndex for sorted JTable)中,我表示我正试图创建一个简单的问题" JTable使用TableModel使用TableModel将ArrayList绑定到JTable。我的目标是 - 现在仍然是 - 保留java的所有内置JTable功能,允许进行单元格编辑,行排序和列重新排列。感谢您的帮助,该功能现在可以使用。

我现在正尝试添加插入和删除表格行的功能。我在这里提供的(更新的)示例有效...除了...在一定的操作序列下," IndexOutOfBoundsException"被扔了。这是我的代码:

package tableexample;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

public final class TableExample extends JFrame {

        List<REItem> REList;
        JTable tblREList;
        JButton btnAddInsertRE, btnDeleteRE;
        JScrollPane spMain;
        JFrame frame;
        Container pane;

    public TableExample() {
        // create and populate the ArrayList
        REList = new ArrayList<>();
        REList.add(new REItem("Template1", "Comment1"));
        REList.add(new REItem("Template2", "Comment2"));
        RETableModel retm = new RETableModel(REList);  // Connect the List to the TableModel
        // create GUI components
        frame = new JFrame ("Table Example");
        btnAddInsertRE = new JButton("Add/Insert");
        btnDeleteRE = new JButton("Delete");
        tblREList = new JTable(retm); 
        tblREList.setAutoCreateRowSorter(true);
        spMain = new JScrollPane(tblREList);
        // add button ActionListeners
        btnAddInsertRE.addActionListener((ActionEvent evt) -> { btnAddInsertREActionPerformed(evt); });
        btnDeleteRE.addActionListener((ActionEvent evt) -> { btnDeleteREActionPerformed(evt); });
        // place GUI components and make the GUI visible
        pane = frame.getContentPane();
        pane.setLayout (null);        
        pane.add(btnAddInsertRE);
        pane.add(btnDeleteRE);
        pane.add(spMain);
        btnAddInsertRE.setBounds (10, 10, 100, 25);
        btnDeleteRE.setBounds (120, 10, 100, 25);
        spMain.setBounds (10, 45, spMain.getPreferredSize().width, spMain.getPreferredSize().height);
        frame.setSize(spMain.getWidth() + 40, spMain.getHeight() + 95);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
        frame.setVisible(true);
    } // end TableExample constructor

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            TableExample notUsed = new TableExample();
        });
    } //end main

    private void btnAddInsertREActionPerformed(ActionEvent evt) {                                             
        // Add a FileSelection object to the ArrayList
        int r = tblREList.getSelectedRow();                         // get row selection, if any
        if (r < 0) {                                                // no row selected
            REList.add(new REItem("NewTemplate", "NewComment"));    //   append new item to end
            r = REList.size()-1;                                    //   get index to new item
        } else {                                                    // else no row selected
            REList.add(r, new REItem("NewTemplate", "NewComment")); //   insert above selected row
        }                                                           // row selected or not
        spMain.setViewportView(tblREList);                          // repaint the updated table
        tblREList.getSelectionModel().setSelectionInterval(r, r);   // select the new row
    }                                            

    private void btnDeleteREActionPerformed(ActionEvent evt) {                                          
        int[] selRows = tblREList.getSelectedRows();                // see if any rows are selected
        if (selRows.length>0) {                                     // at least one row is selected
            for (int r=selRows.length-1; r>=0; r--) {               //   delete each row, from the bottom up,
                REList.remove(r);                                   //     so that indexes are correct and
            }                                                       //       don't change with each delete
            tblREList.clearSelection();                             // clear the row selection data
            spMain.setViewportView(tblREList);                      // repaint the updated table
        } else {                                                    // else no row(s) selected
            JOptionPane.showMessageDialog(null, "Must select at least one item to delete");
        }                                                           // no row selected
    } // end btnDeleteREActionPerformed

    public final class REItem {
        String template;
        String comment;

        public REItem(String tmp, String cmt) {
            this.template = tmp;
            this.comment = cmt;
        }
    } // end class REItem

    public class RETableModel extends AbstractTableModel {

        private List<REItem> reList = new ArrayList();
        private final String[] columnNames = { "Template", "Comment" };

        public RETableModel(List<REItem> list){
             this.reList = list;
        }

        @Override
        public String getColumnName(int column){
             return columnNames[column];
        }

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

        @Override        
        public int getColumnCount() {
            return columnNames.length; 
        }

        @Override
        public Object getValueAt(int row, int column) {
            switch (column) {
                case 0: return reList.get(row).template;
                case 1: return reList.get(row).comment;
               }
               return null; // default case
       }

        @Override
        public boolean isCellEditable(int row, int column) {
            return true;
        }

        @Override
        public Class<?> getColumnClass(int column){
            switch (column){
                case 0: return String.class;
                case 1: return String.class;
            }
            return null; // default case
        }

        @Override
        public void setValueAt(Object value, int row, int column) {
            switch (column) {
                case 0: reList.get(row).template = value.toString(); break;
                case 1: reList.get(row).comment = value.toString(); break;
               }
            // uncommenting the below often causes IndexOutOfBoundsException: Invalid range exception
            fireTableCellUpdated(row, column); 
        } // end setValueAt

    } // end RETableModel

} // end class TableExample

问题可以重现如下:运行上面的例子,点击&#34;添加/插入&#34;按钮向表中追加一个新行,单击任一列标题重新排序表,然后单击&#34;删除&#34;按钮:&#34; IndexOutOfBoundsException&#34;被抛出,表明&#34;行&#34; TableModel的getValueAt方法指定的索引存在缺陷。

我认为这个问题与我的TableModel.getValueAt(也许是.setValueAt ???)方法需要在TableModel列索引和View列索引之间进行转换有关,但是对于我的生活,我可以& #39;弄清楚如何或在何处进行转换。此外,这个问题(Convert modelRowIndex to viewRowIndex for sorted JTable)表明需要在TableModel和View行索引之间进行转换,并且表重新排序必须在索引转换完成之前进行。

尽我所能,我无法弄清楚如何进行转换和/或如何确保在更新和重新排序表后进行转换。我需要听众吗?如果是这样,它应该是什么样的?

您能提供一些澄清和帮助吗?

1 个答案:

答案 0 :(得分:0)

首先,变量名不应以大写字母开头。这是一个Java惯例,它与您发布的代码格式很混乱,使您的代码难以阅读。修复变量并遵循Java约定。

ArrayList只应用于最初向模型添加数据。

之后应该对TableModel进行更新,而不是对ArrayList进行更新。因此,您需要向TableModel添加方法,例如addREItem(...)removeREItem(...)

请参阅Row Table Model,了解如何为给定对象构建自定义TableModel的逐步示例,包括如何添加???(...)和删除???(。 ..)方法。

如果你想从表中删除选定的行,那么请查看:How to delete multiple rows from JTable , database at a time以获取一个工作示例,说明如何使用remove ???(...)方法完成此操作。