Question

I get an error when I remove a row a sorted row in a JTable.

The error appears only when the table is sorted, and I know where the error source is: the method updateRowHeights() in the tableChanged causes an Exception java.lang.ArrayIndexOutOfBoundsException.

I guess that the line int rowHeight = table.getRowHeight(); causes the problem, but I don't know why.

Here is my code:

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;

public class TableExample {

String [] title = new String []      {"Title A", "Title B"};
Object [][] data = new String [][]  {{"aaaaaaaaaaaa aaaaaa aaaaaaa", "bbbbbbbb bbbb bbbbbb bbbbbb"},
                                     {"cccccccccc cccccccc ccccccc", "ddddddd ddd dddddddd dddddd"},
                                     {"eeeeeeeeee eeeeeeee eeeeeee", "fffffff ffff ffffff fffffff"}};


private JTable table;
private JFrame frame;
private DefaultTableModel model;
private JScrollPane pane1;

TableExample() {} //constructor

public JPanel createTable() {

    JPanel panel = new JPanel();

    //creating tables and table models
    model = new DefaultTableModel(data, title);       
    table = new JTable(model);

    table.getModel().addTableModelListener(new TableModelListener() {
        @Override
        public void tableChanged(TableModelEvent e) {
            updateRowHeights();             
        }           
    });

    //enable table sorting
    table.setAutoCreateRowSorter(true);

    pane1 = new JScrollPane(table);
    pane1.setPreferredSize(new Dimension(300,300));        

    updateRowHeights();     

    panel.add(pane1);

    //delete a row after del keystroke
    keyBindings();

    return panel;
}

void showTable() {
    //create and show frame     
    JPanel testPanel = createTable();
    frame = new JFrame();       
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(testPanel);              
    frame.pack();
    frame.setVisible(true);
}//showTable

void updateRowHeights() {
    for (int row = 0; row < table.getRowCount(); row++) {
        int rowHeight = table.getRowHeight();            
            Component comp = table.prepareRenderer(table.getCellRenderer(row, 1), row, 1);                
            rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);                
        table.setRowHeight(row, rowHeight);
    }
}

void keyBindings() {
    int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT; 
    InputMap inputMap = table.getInputMap(condition);
    ActionMap actionMap = table.getActionMap(); 
    inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
    actionMap.put("delete", new AbstractAction() {  
        public void actionPerformed(ActionEvent e) {  
            int row = table.getSelectedRow();
            model.removeRow(row);
        }
    });
}

public static void main(String[] args) {
    TableExample example = new TableExample();  
    example.showTable();
}//main 

}//TableExample

How can I solve this problem?

Was it helpful?

Solution

As noted here, "When using a sorter, always remember to translate cell coordinates." In your delete action, for example,

row = table.convertRowIndexToModel(row);

A similar problem afflicts updateRowHeights(), although I did not pursue this.

Also consider overriding getPreferredScrollableViewportSize(), instead of calling setPreferredSize(); more details here.

As tested:

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;

public class TableExample {

    String[] title = new String[]{"Title A", "Title B"};
    Object[][] data = new String[][]{
        {"aaaaaaaaaaaa aaaaaa aaaaaaa", "bbbbbbbb bbbb bbbbbb bbbbbb"},
        {"cccccccccc cccccccc ccccccc", "ddddddd ddd dddddddd dddddd"},
        {"eeeeeeeeee eeeeeeee eeeeeee", "fffffff ffff ffffff fffffff"}};

    private JTable table;
    private JFrame frame;
    private DefaultTableModel model;
    private JScrollPane pane1;

    public JPanel createTable() {
        JPanel panel = new JPanel();
        //creating tables and table models
        model = new DefaultTableModel(data, title);
        table = new JTable(model);
        //enable table sorting
        table.setAutoCreateRowSorter(true);
        pane1 = new JScrollPane(table);
        panel.add(pane1);
        //delete a row after del keystroke
        keyBindings();
        return panel;
    }

    void showTable() {
        //create and show frame     
        JPanel testPanel = createTable();
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(testPanel);
        frame.pack();
        frame.setVisible(true);
    }//showTable

    void keyBindings() {
        int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
        InputMap inputMap = table.getInputMap(condition);
        ActionMap actionMap = table.getActionMap();
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
        actionMap.put("delete", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int row = table.getSelectedRow();
                row = table.convertRowIndexToModel(row);
                model.removeRow(row);
            }
        });
    }

    public static void main(String[] args) {
        TableExample example = new TableExample();
        example.showTable();
    }//main 

}//TableExample
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top