从 JTable 中删除对象时出现 ArrayOutOfBoundsException

ArrayOutOfBoundsException when removing Objects from a JTable

我是 Java 的新手。我才学了半年。现在我正在为学校做一个项目,但我完全碰壁了:

我基本上是在制作一个程序来管理您自己的图书。我有一个 class 即 "Books",它保存书籍对象的数据。然后是 class "Library",它包含一个 ArrayList of Books。对于 TableModel,我正在使用扩展 AbstractTableModel 的 class ("LibraryTableModel")。然后我有一个显示 table 的 GUI class。

table确实有效,但程序崩溃的情况有两种:

当我将图书添加到空图书馆时,table 没有更新。但是,当我重新启动程序时会添加这本书(我将库 class 保存为 .ser 文件)。

然后是我要问的实例:我有一个按钮可以从 table 中删除图书。 Button 本身工作正常,但是当我取出一本书时,程序会抛出 ArrayOutOfBoundsException。当我重新创建 table 时,它会更新并且这本书会被删除。这里有什么问题,为什么程序崩溃而不是更新 table?

TableModel 代码:

public class LibraryTableModel extends AbstractTableModel
{
private String[] columnNames = {"Titel", "Autor", "Status", "Genre", "Verlag", "Seitenzahl", "ISBN", "Sprache", "Bewertung"};
private Object[][] data = {};
ArrayList<Book> lib;

public LibraryTableModel(Library l)
{
    //This Method returns the ArrayList in the Library class
    lib = l.getList();

    int libSize = lib.size();
    data = new Object[bib.size()][];

    for (Book b : lib)
    {
        int index = bib.indexOf(b);
        //(...)
        //CODE HERE gets all the data that is supposed to be displayed 
        //from each book in the ArrayList      
        Object[] oA = {tit, aut, sta, gen, ver, sei, isb, spr, bew};

        data[index] = oA;
    }
}

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

public int getRowCount()
{
    return data.length;
}

public String getColumnName(int col) 
{
    return columnNames[col];
}

public Object getValueAt(int row, int col) 
{
    return data[row][col];
    //When I try to remove a Book, the ArrayOutOfBounds Exception comes from here
}

public Class getColumnClass(int c) 
{
    return getValueAt(0, c).getClass();
}

public void setValueAt(Object value, int row, int col) 
{
    data[row][col] = value;
    fireTableCellUpdated(row, col);
}

public void removeRow(int row)
{
    lib.remove(row);
    fireTableRowsDeleted(row, row);
}

GUI class 中围绕 table 和 table 模型的代码:

public class GUI implements ActionListener
{
JTable table;
LibraryTableModel model;
TableRowSorter<BibliothekTableModel> sorter;
Library lib;
JMenuItem deleteBook;

(...) 库是通过.ser 文件加载的

public void showTable() //This method is envoked in the GUI constructor through pressing a button
 {
    model = new LibraryTableModel(lib);
    table.setModel(model);

    deleteBook.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            int row = table.getSelectedRow();
            model.removeRow(row);

            //Code that saves the library at this point

            table.setModel(new LibraryTableModel(lib));
        }
    });

    popupMenu.add(deleteBook);
    table.setComponentPopupMenu(popupMenu);

    sorter = new TableRowSorter<BibliothekTableModel>(model);
    table.setRowSorter(sorter);
    JScrollPane scrollTable = new JScrollPane(table);

    //Next is code, that adds this ScrollPane to my Frame
 }

When I add a Book to an empty Library, the table doesn't update. However, the Book IS added when I start the program anew (I save the Library class as a .ser file).

没有提供任何信息来说明它是如何工作的...什么是 .ser 文件?

Then the instance which I am asking about: I have a button that removes Books from the table. the Button itself works fine, but when I remove a book, the program throws an ArrayOutOfBoundsException. When I create the table anew, it updates and the book is removed. What is the problem here, why does the program crash instead of update the table?

有两个问题...

首先,因为您在 table 上使用 RowSorterJTable#getSelectedRow 返回的可视行索引和模型中的物理行索引将不相同, 你需要使用 JTable#convertRowIndexToModel

int row = table.getSelectedRow();
row = table.convertRowIndexToModel(row);
model.removeRow(row);

//Code that saves the library at this point

其次,您要从 lib 中删除图书,但不会更新内部缓存...

public void removeRow(int row)
{
    lib.remove(row);
    fireTableRowsDeleted(row, row);
}

该模型未使用 lib 作为数据源,而是使用了 data 数组,您尚未更新该数组。

虽然您可以简单地重建 data 数组,但更好的解决方案是摆脱它并直接使用 lib,例如...

public class LibraryTableModel extends AbstractTableModel {

    private String[] columnNames = {"Titel", "Autor", "Status", "Genre", "Verlag", "Seitenzahl", "ISBN", "Sprache", "Bewertung"};
    private Object[][] data = {};

    private Library lib;

    public LibraryTableModel(Library l) {
        lib = l;
    }

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

    public int getRowCount() {
        return lib.getList().size();
    }

    public String getColumnName(int col) {
        return columnNames[col];
    }

    public Object getValueAt(int row, int col) {
        Book book = lib.getList().get(row);
        Object value = null;
        switch (col) {
            case 0:
                value = ...;
                break;
            case 1:
                value = ...;
                break;
            case 2:
                value = ...;
                break;
            case 3:
                value = ...;
                break;
            case 4:
                value = ...;
                break;
            case 5:
                value = ...;
                break;
            case 6:
                value = ...;
                break;
            case 7:
                value = ...;
                break;
            case 8:
                value = ...;
                break;
        }
        return value;
//When I try to remove a Book, the ArrayOutOfBounds Exception comes from here
    }

    public Class getColumnClass(int c) {
        // Don't do this, know the actualy value and return it
        // Otherwise you could end up with a NullPointerException
        return getValueAt(0, c).getClass();
    }

    public void setValueAt(Object value, int row, int col) {
        // Use a simular technquie to getValueAt to extract the Book for the give
        // row and update the Book's attributes
        fireTableCellUpdated(row, col);
    }

    public void removeRow(int row) {
        lib.remove(row);
        fireTableRowsDeleted(row, row);
    }

}