索引越界插入行、排序表和删除行后的异常



在上一个问题(将 modelRowIndex 转换为 viewRowIndex 以进行排序的 JTable(中,我表示我正在尝试创建一个"简单"的 JTable,它使用 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

该问题可以按如下方式重现:运行上述示例,单击"添加/插入"按钮将新行附加到表中,单击任一列标题以重新排序表,然后单击"删除"按钮: 抛出"IndexOutOfBoundsException",表示 TableModel 的 getValueAt 方法指定的"行"索引有缺陷。

我认为这个问题与我的 TableModel.getValueAt(也许还有 .setValueAt ???(方法需要在 TableModel 列索引和视图列索引之间进行转换有关,但是,对于我的一生,我无法弄清楚如何或在哪里进行转换。 Morevover,这个问题(将模型行索引转换为视图行索引以进行排序的JTable(表明需要在TableModel和View行索引之间进行转换,并且必须在索引转换完成之前进行表重新排序。

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

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

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

数组列表只应用于最初向模型添加数据。

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

有关如何为给定对象构建自定义 TableModel 的分步示例,包括代码的添加方式,请参阅行表模型???(...)并删除???(...)方法。

如果您想从表中删除选定的行,请查看: 如何从 JTable 中删除多行 ,一次数据库以获取工作示例,该示例显示了如何使用删除来完成此操作???(...)方法。

最新更新