0

I apologize for asking a question that's been asked a lot in various forms, but I have yet to find a complete answer that works. All I'm trying to do is to append a row to a tablemodel. I've tried doing it in a lot of different ways but always run into similar issues (or sometimes new and exciting ones). Anyway, when I try to add the row I get an "ArrayIndexOutOfBoundsException" error. I've marked the line where the error occurs in the code below. I've also included the errors I've seen and debugging output I've been using. I'm aware I don't really need to extend the DefaultTableModel for what you see here, but this is a stripped down version that I've been working with to chase the bug.

Exception:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 2 > 0 at java.util.Vector.insertElementAt(Vector.java:594) at javax.swing.table.DefaultTableModel.insertRow(DefaultTableModel.java:374) at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:350) at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:361) at SMC.RoleCard$1.actionPerformed(RoleCard.java:69) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) at java.awt.Component.processMouseEvent(Component.java:6505) at javax.swing.JComponent.processMouseEvent(JComponent.java:3321) at java.awt.Component.processEvent(Component.java:6270) at java.awt.Container.processEvent(Container.java:2229) at java.awt.Component.dispatchEventImpl(Component.java:4861) at java.awt.Container.dispatchEventImpl(Container.java:2287) at java.awt.Component.dispatchEvent(Component.java:4687) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422) at java.awt.Container.dispatchEventImpl(Container.java:2273) at java.awt.Window.dispatchEventImpl(Window.java:2719) at java.awt.Component.dispatchEvent(Component.java:4687) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:729) at java.awt.EventQueue.access$200(EventQueue.java:103) at java.awt.EventQueue$3.run(EventQueue.java:688) at java.awt.EventQueue$3.run(EventQueue.java:686) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87) at java.awt.EventQueue$4.run(EventQueue.java:702) at java.awt.EventQueue$4.run(EventQueue.java:700) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.awt.EventQueue.dispatchEvent(EventQueue.java:699) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Debug Output:

There are 2 elements in roleData
roleData has 2 elements
Performing WHILE loop
tableData[0][0] is assigned ECC
tableData[0][1] is assigned 1
Performing WHILE loop
tableData[1][0] is assigned Portal
tableData[1][1] is assigned 2
Called getColumnCount()
Returned 2
tableDate has 2 columns and 2 rows.
Called getColumnCount()
Returned 2
Called getColumnName()
Returned Role
Called getColumnCount()
Returned 2
Called getColumnName()
Returned Sort Order
Called getColumnCount()
Returned 2
arg is :Role Data:
Clicked on Role
Called getColumnClass()
Called getColumnClass()
Called getColumnClass()
Called getColumnClass()
B: There are 2 rows in RoleTableModel
Add was pressed

Code:

package SMC;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 * @author Larry Krigbaum
 */
public class RoleCard
{
    public JPanel getRoleCard()
    {
        final JPanel roleCard = new JPanel();
        roleCard.setLayout(new BoxLayout(roleCard, BoxLayout.PAGE_AXIS));
        roleCard.setAlignmentX(Component.CENTER_ALIGNMENT);
        JPanel role_title = new JPanel();
        role_title.add(new JLabel(" "));
        role_title.add(new JLabel("Configure SAP Roles"));
        role_title.add(new JLabel(" "));
        roleCard.add(role_title);

        final JPanel role_table = new JPanel();
        String[] roleColumnNames = {"Role", "Sort Order"};
        ArrayList<Role> roleData = Role.loadRoleData();
        System.out.println("There are " + roleData.size() + " elements in roleData");
        //ArrayList<Role> roleData = null;
        final RoleTableModel roleTableModel = new RoleTableModel(roleColumnNames, roleData);
        JTable roleEditTable = new JTable(roleTableModel);
        roleEditTable.setAutoCreateRowSorter(true);
        //final DefaultTableModel roleTableModel = (DefaultTableModel) roleEditTable.getModel();
        //final JTable roleEditTable = getRoleTable();
        role_table.add(new JScrollPane(roleEditTable));                         // ScrollPane needed to show headers
        roleCard.add(role_table);

        JPanel buttonPanel = new JPanel();
        JButton addButton = new JButton("Add");
        addButton.setActionCommand("Add");
        JButton deleteButton = new JButton("Delete");
        deleteButton.setActionCommand("Delete");
        final JButton cancelButton = new JButton("Cancel");
        cancelButton.setActionCommand("Cancel");
        cancelButton.setEnabled(false);
        buttonPanel.add(addButton);
        buttonPanel.add(deleteButton);
        buttonPanel.add(cancelButton);
        roleCard.add(buttonPanel);
        addButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                System.out.println("B: There are " + roleTableModel.getRowCount() + " rows in RoleTableModel");
                System.out.println("Add was pressed");
                cancelButton.setEnabled(true);
                Object[] newRole = null;
                roleTableModel.addRow(newRole);
                //Object[] newRole = new Object[] {" ", " "};
                System.out.println("A: There are " + roleTableModel.getRowCount() + " rows in RoleTableModel");
                //roleTableModel.setRowCount((roleTableModel.getRowCount()) + 1);
                System.out.println("B: There are " + roleTableModel.getRowCount() + " rows in RoleTableModel");
                roleTableModel.fireTableRowsInserted(roleTableModel.getRowCount(), roleTableModel.getRowCount());
                roleTableModel.fireTableDataChanged();
            }
        });
        deleteButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                System.out.println("Delete was pressed");
                cancelButton.setEnabled(true);
            }
        });
        cancelButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                System.out.println("Cancel was pressed");
                cancelButton.setEnabled(false);
            }
        });

        return roleCard;
    }

class RoleTableModel extends DefaultTableModel
{
    private String[] roleColumnNames = {"Role", "Sort Order"};
    private Object[][] tableData;

    public RoleTableModel(String[] roleColumnNames, ArrayList<Role> roleData)
    {
        System.out.println("roleData has " + roleData.size() + " elements");
        tableData = new Object[roleData.size()][2];
        Role role = new Role();

        Collections.sort(roleData, Role.MakeComparator);
        Iterator rolesOrderByRole = roleData.iterator();
        int i = 0;
        while (rolesOrderByRole.hasNext())
        {
            System.out.println("Performing WHILE loop");
            role = (Role)rolesOrderByRole.next();
            tableData[i][0] = role.xrole;
            System.out.println("tableData[" + i + "][0] is assigned " + tableData[i][0]);
            tableData[i][1] = role.sortOrder;
            System.out.println("tableData[" + i + "][1] is assigned " + tableData[i][1]);
            i++;
        }
        System.out.println("tableDate has " + getColumnCount() + " columns and " + getRowCount() + " rows.");
    }

   @Override
    public int getColumnCount() 
    {
        System.out.println("Called getColumnCount()");
        System.out.println("Returned " + roleColumnNames.length);
        return roleColumnNames.length;
    }

    @Override
    public int getRowCount()
    {
       if (tableData == null)
           return 0;
       return tableData.length;
    }

    @Override
    public String getColumnName(int col) 
    {
        System.out.println("Called getColumnName()");
        System.out.println("Returned " + roleColumnNames[col]);
        return roleColumnNames[col];
    }

    @Override
    public Object getValueAt(int row, int col) 
    {
        return tableData[row][col];
    }

    @Override
    public Class getColumnClass(int c) 
    {
        System.out.println("Called getColumnClass()");
        return getValueAt(0, c).getClass();
    }

    /*
     * Don't need to implement this method unless your table's
     * editable.
     */
    @Override
    public boolean isCellEditable(int row, int col) 
    {
        System.out.println("Called isCellEditable()");
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        return true;
    }

    /*
     * Don't need to implement this method unless your table's
     * data can change.
     */
    @Override
    public void setValueAt(Object value, int row, int col)
    {
        System.out.println("Called setValueAt()");
        tableData[row][col] = value;
        fireTableCellUpdated(row, col);
    }
}
4
  • Which line of code is causing the error? You should provide a smaller example if you can. Commented Jul 17, 2013 at 18:01
  • Have you overwritten the insertRow method? I think you are mixing where the data should be stored, which I guess that in your case is in tableData, and where the data is being added. Commented Jul 17, 2013 at 18:08
  • Sorry, I intended to mark the line and forgot. The specific line the exception points to is "roleTableModel.addRow(newRole);" in the overide of actionPerformed in the AddButton.addActionListener block. Commented Jul 17, 2013 at 18:12
  • No I haven't tried overwriting the insertRow method. I kept the data as an Object[][] because I thought that should work with the addRow(Object[]) method. What kind of changes would I make to addRow? Commented Jul 17, 2013 at 18:15

1 Answer 1

1

You're creating a table model by extending DefaultTableModel. But instead of delegating to its methods to store the data, you store them in a separate array of data. And you override some methods and not others. The result is that sometimes, the methods of the superclass are used, that try to get and insert data in the vector held by the super class, and sometimes, the subclass methods are used that get and set values from/to the subclass array of data.

If you need to define a custom TableModel implementation, either extend AsbtractTableModel, and define everything as you want, or extend DefaultTableModel but don't add define any field. Only override methods that need to be overridden, and delegate to the superclass methods.

Except for getColumnClass(), I don't see any reason to override any method in DefaultTableModel.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, JB. I'm going to think about what you're saying and dig into it and see if this will get me over the hump. I thought I was following the examples on Oracle, but I obviously need to look at those some more. You're absolutely right about needlessly extending the DefaultTableModel methods. I thought since the oeverrides were the same as the ones in DefaultTableModel that I was okay, but I can see how something may not be getting propagated in the background. I'll get rid if those overrides.
JB, I went back and got rid of the RoleTableModel I created and sent everything through Default and it's working fine. I'll be heading back to my own table model as I add some features but I'll keep it incremental and try to to step on myself again. Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.