Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ArrayIndexOutOfBoundsException with DefaultTableModel

8 views
Skip to first unread message

Aloys Oberthuer

unread,
Apr 15, 2004, 5:54:42 PM4/15/04
to
Hi everyone,

i have got a problem with JTable. I created a small panel which includes
a JTable (in a JScrollPane) with a DefaultTableModel as model and 3
Buttons to add and remove rows and to clear the whole table. The problem
is after deleting a row, and clicking on the row which is now the last,
I always get ArrayIndexOutOfBoundsExceptions (see the StackTrace below).


I create the Table as follows:

DefaultTableModel dftM = new DefaultTableModel(2, 1);

tbl = new JTable();
tbl.setAutoCreateColumnsFromModel(false); // create my own ColumnModel
tbl.setShowHorizontalLines(true);
tbl.setShowVerticalLines(true);
tbl.setModel(dftM);

// build table column(s), custom renderer(s) and editor(s), etc.
// see below

All I do is invoke the following method in my code on a "delete row"
button action:
private void rowDelete() {
int row = tbl.getSelectedRow();
((DefaultTableModel)tbl.getModel()).removeRow(row);
}

The table does redraw with one row less, but as I try to select another
row, I always get the Exception. The same thing happens after clearing
the Table which I do as follows:

public void tableDataReset() {
DefaultTableModel dftM = new DefaultTableModel(1, 1);
tbl.setModel(dftM);
}

I.e. I do create a new DefaultTableModel and get the same problem. It
looks like changing the model (deleting a row, replacing the model) did
not really affect the model or leaves it in an inconsistent state, which
I find especially strange with replacing the model. Sometimes after
deleting a row and adding an empty new one the 'empty' row contains the
content of the deleted row, which points in the same direction for me.
I tried using tbl.tableChanged(new TableModelEvent(dftM)) but that did
not help either. I have included the whole (executable) class and the
stacktrace - any help would be greatly appreciated. I use J2SE 1.4.2 on
a WindowsXp Sp1 System.

Aloys


CODE:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;


public class SimpleTablePanel extends JPanel {

private JTable tbl;
private JScrollPane jsp;
private JPanel pnlTable, pnlButtons;
private JButton btAdd, btRemove, btClear;


public SimpleTablePanel(String title, int tWidth, int tHeight) {
super();

createPanelTable(title, tWidth, tHeight);
createPanelButtons();

this.setLayout(new BorderLayout());
this.add(pnlTable, BorderLayout.CENTER);
this.add(pnlButtons, BorderLayout.SOUTH);
}


private void createPanelButtons() {
// create Button Panel
pnlButtons = new JPanel(new FlowLayout(FlowLayout.LEFT));

btAdd = new JButton("Add");
btAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent aE){
SimpleTablePanel.this.rowAdd();
}
});
btRemove = new JButton("Del");
btRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent aE) {
SimpleTablePanel.this.rowDelete();
}
});
btClear = new JButton("Clr");
btClear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent aE) {
SimpleTablePanel.this.tableDataReset();
}
});

pnlButtons.add(btAdd);
pnlButtons.add(btRemove);
pnlButtons.add(btClear);
}

private void createPanelTable(String title, int tWidth, int tHeight) {
pnlTable = new JPanel();

DefaultTableModel dftM = new DefaultTableModel(2, 1);

// next create Table
tbl = new JTable();
tbl.setAutoCreateColumnsFromModel(false); // create my own ColumnModel
tbl.setShowHorizontalLines(true);
tbl.setShowVerticalLines(true);
tbl.setModel(dftM);

// and build table column
TableCellRenderer renderer = new DefaultTableCellRenderer();

JTextField txt = new JTextField(20);
txt.setBorder(null);
TableCellEditor editor = new DefaultCellEditor(txt);

((DefaultCellEditor)editor).setClickCountToStart(1);

TableColumn column = new TableColumn(0, tWidth, renderer, editor);
column.setHeaderValue(title);
tbl.addColumn(column);

// and put it in a JScrollPane
jsp = new JScrollPane(tbl);
jsp.setPreferredSize(new Dimension(tWidth,tHeight));
pnlTable.add(jsp, BorderLayout.CENTER);
}

private void rowAdd() {
int row = tbl.getSelectedRow();
((DefaultTableModel)tbl.getModel()).insertRow(row+1, new String[] {""});
}
private void rowDelete() {
int row = tbl.getSelectedRow();
((DefaultTableModel)tbl.getModel()).removeRow(row);
}
public void tableDataReset() {
DefaultTableModel dftM = new DefaultTableModel(1, 1);
tbl.setModel(dftM);
}

public static void main(String[] args) {

JFrame jf = new JFrame("Testframe");
jf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});

SimpleTablePanel jsF = new SimpleTablePanel("Table", 400, 300);
jf.getContentPane().add(jsF, BorderLayout.CENTER);
jf.pack();
jf.setVisible(true);
}
}


STACKTRACE:
java.lang.ArrayIndexOutOfBoundsException: 2 >= 2
at java.util.Vector.elementAt(Vector.java:431)
atjavax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:633)
at javax.swing.JTable.setValueAt(JTable.java:1794)
at javax.swing.JTable.editingStopped(JTable.java:3167)
atjavax.swing.AbstractCellEditor.fireEditingStopped(AbstractCellEditor.java:124)
at
javax.swing.DefaultCellEditor$EditorDelegate.stopCellEditing(DefaultCellEditor.java:329)
at javax.swing.DefaultCellEditor.stopCellEditing(DefaultCellEditor.java:214)
at javax.swing.JTable.editCellAt(JTable.java:2510)
at
javax.swing.plaf.basic.BasicTableUI$MouseInputHandler.adjustFocusAndSelection(BasicTableUI.java:510)
at
javax.swing.plaf.basic.BasicTableUI$MouseInputHandler.mousePressed(BasicTableUI.java:494)
at java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:222)
at java.awt.Component.processMouseEvent(Component.java:5097)
at java.awt.Component.processEvent(Component.java:4897)
at java.awt.Container.processEvent(Container.java:1569)
at java.awt.Component.dispatchEventImpl(Component.java:3615)
at java.awt.Container.dispatchEventImpl(Container.java:1627)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3483)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3195)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3128)
at java.awt.Container.dispatchEventImpl(Container.java:1613)
at java.awt.Window.dispatchEventImpl(Window.java:1606)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:456)
at
java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:201)
at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:145)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:137)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:100)

A.Buschmann

unread,
Apr 17, 2004, 12:39:41 PM4/17/04
to
Hi Aloys,

the stacktrace says, the problem comes from the "setValueAt()"-Method- but
you are deleting,
not editig.
Or are you??
With the DefaultTableModel, the "isCellEditable(int, int)"-Method returns
simply "true".
When you select a row with your mouse, it is open for edit. (Select row 2 of
2)
By clicking the delete-button, the edited-cell is not properly saved.
The row where the edited cell is in becomes deleted.
Now there is no row selected, but the JTable remembers that the first column
in the second
row was in edit-mode.
When clicking on row one, the JTable sees: You are leaving the edited field.
So JTable tries to save your edit. (In row 2 which does no longer exist)

The exception will not occur, if you use the arrow-keys in the JTable:
1. Click in row one
2. Move with the down-key to row two
The blinking cursor will vanish and the entire row becomes an
highlighted border
3. Delete row two. (Click on "Del"-Button)
4. Click on row one.
No Exception occurs.

The DefaultTableModel is o.k., but the JTable does not realize, that the
edited row has
been removed.

If you don't need to change the cells, extend DefaultTableModel and
overwrite
simply the "isCellEditable(int, int)"-Method:

public boolean isCellEditable(int row, int column) {
return false;
}

Else,
you have to call the "stopCellEditing()"-Method from DefaultCellEditor-Class
before you start with
deleting the row.
To get the CellEditor, the JTable has the "getCellEditor()"-Method.
As far as I know, the "getCellEditor()"-Method returns "null", when
no cell is edited.
Your rowDelete() should look like this:


private void rowDelete() {
int row = tbl.getSelectedRow();

if (row > -1) {
DefaultCellEditor dce = (DefaultCellEditor)tbl.getCellEditor();
if (dce != null) dce.stopCellEditing();
((DefaultTableModel)tbl.getModel()).removeRow(row);
}
}

hope this helps.

Alex


Aloys Oberthuer

unread,
Apr 22, 2004, 12:32:01 PM4/22/04
to


Thanks a lot, invoking the stopCellEditing() method does indeed solve the problem. Now my rowDelete() method does look
like this, which actually does pretty much the same (I'd say your's is even a little more elegant) :
private void rowDelete() {
if(tbl.getCellEditor() != null)
((DefaultCellEditor)tbl.getCellEditor()).stopCellEditing();

int row = tbl.getSelectedRow();
if((row >= 0) && (tbl.getRowCount()>1)) {
DefaultTableModel tm = (DefaultTableModel)tbl.getModel();
tm.removeRow(row);
tbl.repaint();
}
}

Searching the web I got the idea that quite a lot had the same problem, wonder why some things have to be so complicated.
Thanks, Aloys

0 new messages