-1

I'm just starting out with swing, but I've been stuck on this issue for about a week and I've tried everything I can think. I'm trying to update the table model as the result of a click on a column header and getting an ArrayIndexOutOfBoundsException.

I've simplified the code here, but can someone please explain why this:

package gradebook.model.courseTable;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class CourseTableTest extends JTable {
    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
                public void run(){
                    JFrame frame = new JFrame();
                    frame.add(new JScrollPane(new CourseTable()));
                    frame.setVisible(true);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                }
            });

        }

    public CourseTableTest(){
        super(3, 3);

        this.tableHeader.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                setModel(new DefaultTableModel(3, 3));
            }
        });
    }
}

throws this when clicked?:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.Vector.elementData(Unknown Source)
    at java.util.Vector.elementAt(Unknown Source)
    at javax.swing.table.DefaultTableColumnModel.getColumn(Unknown Source)
    at javax.swing.JTable.getCellRenderer(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paintDraggedArea(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
    at javax.swing.plaf.ComponentUI.update(Unknown Source)
    at javax.swing.JComponent.paintComponent(Unknown Source)
    at javax.swing.JComponent.paint(Unknown Source)
    at javax.swing.JComponent.paintToOffscreen(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
    at javax.swing.RepaintManager.paint(Unknown Source)
    at javax.swing.JComponent._paintImmediately(Unknown Source)
    at javax.swing.JComponent.paintImmediately(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$700(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(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.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)
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.Vector.elementData(Unknown Source)
    at java.util.Vector.elementAt(Unknown Source)
    at javax.swing.table.DefaultTableColumnModel.getColumn(Unknown Source)
    at javax.swing.JTable.getCellRenderer(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paintDraggedArea(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
    at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
    at javax.swing.plaf.ComponentUI.update(Unknown Source)
    at javax.swing.JComponent.paintComponent(Unknown Source)
    at javax.swing.JComponent.paint(Unknown Source)
    at javax.swing.JComponent.paintToOffscreen(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
    at javax.swing.RepaintManager.paint(Unknown Source)
    at javax.swing.JComponent._paintImmediately(Unknown Source)
    at javax.swing.JComponent.paintImmediately(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$700(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(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.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)

Edit Some of you have asked why I would change the model during a click of the column header. In my application, the table columns represent a school assignment. When the header is clicked it opens a dialog box that allows the user to either modify or delete the assignment. If the user clicks delete I would like to remove the column from the table. But any time I try to change the table structure within the click handler I get this error.

hooda
  • 105
  • 6
  • `public void mousePressed(MouseEvent e) { setModel(new DefaultTableModel(3, 3));` That seems an odd time to be setting the model. For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example - note it should have a `main(String[])` and be runnable). – Andrew Thompson Oct 24 '14 at 02:01
  • `public class CourseTable extends JTable..` In all the times I've used `JTable` I've needed to extend it (thinks carefully) **..never.** Why do you think you need to? – Andrew Thompson Oct 24 '14 at 02:04
  • 1
    You've set up an inconsistency between the data model, column model, the table and the table header – MadProgrammer Oct 24 '14 at 02:04
  • The real question is, why are you changing the `TableModel` when the header is clicked, what is it you are trying to achieve? – MadProgrammer Oct 24 '14 at 02:28
  • Edited the question to provide MCVE and explanation for what I'm trying to accomplish. – hooda Oct 24 '14 at 12:36

1 Answers1

2

The MouseListener must be doing some processing and doesn't like you changing the data in the middle of the processing.

Try:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
            setModel(new DefaultTableModel(3, 3));
    }
});

This will let the MouseListener code finish executing before you change the model.

The real question is why would you change the model when you click on the header?

Edit:

As noted by MadProgrammer the first suggestion doesn't work.

As another hack if you are just trying to clear the data in the model you can use:

@Override
public void mousePressed(MouseEvent e)
{
    model.setRowCount(0);
    model.setRowCount(3);
}

If you want a table with a completely different structure then I would suggest you do something like:

@Override
public void mousePressed(MouseEvent e)
{
    scrollPane.setViewportView( new JTable(4, 4) );
}
camickr
  • 321,443
  • 19
  • 166
  • 288
  • I got it to work by using a single use Swing `Timer` set to about 125 milliseconds, but this by no means a viable solution... – MadProgrammer Oct 24 '14 at 02:09
  • 1
    You mean I should be testing my suggestions first :) Oh well, next time. @MadProgrammer, Yes I guess the problem is that clicking on the header causes the selection model to be updated and the table/tableheader needs to be repainted, but the model is changed before all this is done. I agree sleeping longer is not a viable solution. Added a couple of possible solutions. This time I tested ;) – camickr Oct 24 '14 at 02:25
  • `SwingUtilities.invokeLater` was my first thought too ;) – MadProgrammer Oct 24 '14 at 02:28
  • Thanks for the suggestion, but I should have mentioned that I already tried invokeLater. I should also mention that I do not get this error if I add the MouseListener to the JTable itself, but that does not work for my use case. – hooda Oct 24 '14 at 02:37
  • @camickr Actually if you read my question I asked why does this happen? The idea that the MouseListener must be doing some processing doesn't make much sense to me since everything should be executing on the EDT and therefore synchronously. – hooda Oct 24 '14 at 13:24
  • As for the two suggestions, setting the row count works, however setting the column count results in the same error. The second suggestion of creating a brand new table does work but it doesn't really answer my question. – hooda Oct 24 '14 at 13:25
  • @hooda, `Actually if you read my question I asked why does this happen?` And if you really want to know then look at the source code. We've given you the basics, that the repaint is out of sync. Repainting of any component is scheduled by the RepaintManager. So something is out of sync from the time the request is made until the time is done. I don't know what, but you have been given a solution to use a Timer to allow the repainting to complete before you reset the structure of the table header. That is the best we can do without rewriting the whole UI for the JTable. – camickr Oct 24 '14 at 15:12
  • @hooda, `creating a brand new table does work but it doesn't really answer my question.` It provides you with a realistic solution. `If the user clicks delete I would like to remove the column from the table.` I don't understand why this doesn't work. It sounds like you are using the mousePressed to display a menu of options. Then you select the "delete" option. Therefore the table change will not be executed in the MouseListner. Post a proper `MCVE` that demonstrates the real problem. See [Table Column Manager](http://tips4java.wordpress.com/2011/05/08/table-column-manager/) for a solution. – camickr Oct 24 '14 at 15:33