Bent
Bent

Reputation: 1385

Java JTable / DefaultTableModel java.lang.ArrayIndexOutOfBoundsException

In my application I am working with a JTable containing a DefaultTableModel. Everything is working fine until the point I want to clear my table and start with a new DefaultTableModel. The clearing process is done like this:

public static JTable table = new JTable;
public static CustomTableModel model = new CustomTableModel();

[...]

table.setModel(new DefaultTableModel());
model = new CustomTableModel();
model.createEmptyModel();
table.setModel(model); 
// model.save(config.getDatabaseFile(), table); // <<< Reference A
model.initColumModel(table);

So far so good. Now my CustomTableModel extends from DefaulTableModel and adds some of my custom methods. One of them is createEmptyModel() which looks like this:

public void createEmptyModel() {
    model = new DefaultTableModel(new Object[][] {},
            new String[] { "Lfd. Nr.", "FB Nr.", "Auftr. / Meld. Nr.", "Betra Nr.", "Datum", "Bahnhof", "Str. Km.",
                    "Sprz.", "Arb. Zeit", "Mitarbeiter", "Auftrag / Objekt(e)", "Anmerkungen", "Fertig" }) {

        private static final long serialVersionUID = -4325766838779239822L;
        @SuppressWarnings("rawtypes")
        Class[] columnTypes = new Class[] { Integer.class, String.class, Long.class, Long.class, String.class,
                String.class, String.class, String.class, String.class, String.class, String.class, String.class, Boolean.class };

        @SuppressWarnings({ "unchecked", "rawtypes" })
        public Class getColumnClass(int columnIndex) {
            return columnTypes[columnIndex];
        }
    };
    // this sequentialNumber is just some object which contains a counter. Not important here!
    sequentialNumber.reset();
}

With this method I initialize my model with all the needed vectors and types.

When model.initColumModel(table) get's called my application crashes with this exception:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
    at java.util.Vector.elementAt(Unknown Source)
    at javax.swing.table.DefaultTableColumnModel.getColumn(Unknown Source)
    at somepacket.CustomTableModel.initColumModel(CustomTableModel.java:36)
    at somepacket.DBDatabaseSystem.createNewDatabase(DBDatabaseSystem.java:416)
    at somepacket.DBDatabaseSystem$4.actionPerformed(DBDatabaseSystem.java:155)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.AbstractButton.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

My initColumModelmethod is declared like this:

public void initColumModel(JTable table) {
    // doing this here to avoid calling table.getColumnModel multiple times
    TableColumnModel columnModel = table.getColumnModel();

    columnModel.getColumn(0).setResizable(false);
    columnModel.getColumn(0).setPreferredWidth(50);
    columnModel.getColumn(1).setResizable(false);
    columnModel.getColumn(1).setPreferredWidth(50);
    columnModel.getColumn(2).setResizable(false);
    columnModel.getColumn(2).setPreferredWidth(81);
    columnModel.getColumn(3).setResizable(false);
    columnModel.getColumn(3).setPreferredWidth(81);
    columnModel.getColumn(4).setPreferredWidth(81);
    columnModel.getColumn(5).setPreferredWidth(134);
    columnModel.getColumn(6).setPreferredWidth(123);
    columnModel.getColumn(7).setPreferredWidth(95);
    columnModel.getColumn(8).setPreferredWidth(95);
    columnModel.getColumn(9).setPreferredWidth(226);
    columnModel.getColumn(10).setResizable(true);
    columnModel.getColumn(10).setPreferredWidth(300);
    columnModel.getColumn(11).setResizable(true);
    columnModel.getColumn(11).setPreferredWidth(102);
    columnModel.getColumn(12).setResizable(false);
    columnModel.getColumn(12).setMinWidth(45);
    columnModel.getColumn(12).setMaxWidth(45);
}

From what I can the problem is that my CustomTableModel has no columns after it's creation. So what I tried was adding a new row to the table and call initColumModel afterwards, but this did not help. The application still crashes. The only way to prevent the crash is saving the model before calling my initColumModel method. But this makes no sense, see for yourself, this is my save method, that changes nothing on the model nor add any column:

[...]

    try {
            // undo all selections to prevent user from editing while saving
            table.clearSelection(); 
            // prevent saving when user is editing a cell
            if (table.isEditing()) { 
                table.getCellEditor().stopCellEditing();
            }

            fos = new FileOutputStream(filename);
            out = new ObjectOutputStream(fos);

            table.setModel(new DefaultTableModel());
            // detach model from table prior serializing
            out.writeObject(model);
            // re-attach table model
            table.setModel(model); 
            // set layout again
            initColumModel(table); 

            out.writeObject(sequentialNumber);

[...]

After saving my model, it appears in the JTable and everything works perfect. How could this be? I tried detaching and reattaching the model from and to the table manually before calling initColumModel but this did not help either.

Basically I am lost now, how can I solve my problem? Or am I doing something obviously wrong?

Thanks in advance!

Upvotes: 0

Views: 2239

Answers (2)

camickr
camickr

Reputation: 324088

If you just want to clear the data in the model then you just use:

model.setRowCount(0);

if you want to replace the TableModel with a new structure (ie. new column headings and data) then you just create a new TableModel:

TableModel model = new DefaultTableModel(...);
table.setModel( model );

From what I can the problem is that my CustomTableModel has no columns after it's creation

Sure it has columns if you implement the getColumnCount() and getColumnNames() method correctly.

The TableColumnModel of the JTable is not created until you actuallyl set a model to the table. When you use new DefaultTableModel() you are creating a TableColumnModel with zero columns. So add a proper TableModel to the table if you want columns to exist.

// detach model from table prior serializing

Why are you detaching the model from the table? This is unnecessary.

Instead of serializing the DefaultTableModel you might want to look at using an XMLEncoder which is the recommend approach for long term storage of objects. See: Saving content of Interactive JTable to .txt file to read it upon next run for a working example of this approach.

Upvotes: 1

milez
milez

Reputation: 2201

You are accessing columns that the model does not have actually. Before each of your columnModel.get()... call add

columnModel.addColumn(new TableColumn(int index));

This question is helpful: java.lang.ArrayIndexOutOfBoundsException: 0 >= 0 attempting to populate JTable

There is also noted that the same error is thrown if you edit the columns from a non GUI thread, check that this is not the issue

Upvotes: 0

Related Questions