views:

59

answers:

3

I'm using a JTabbedPane in my application and I listen to its changes with ChangeListener so that I can know which tab is currently selected. So my stateChanged method is;

public void stateChanged(ChangeEvent e) {
    currentPageIndex = jTabbedPane.getSelectedIndex();
}

But while I'm adding new tabs to the JTabbedPane it throws an ArrayIndexOutOfBoundsException in the method above, I don't know why. Some suggested for a similar case that this is a bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4873983, but as you'll see some says the solution is to work with Swing from EventDispatchThread.

What does it mean, do they mean the SwingUtilities.invokeLater thing? Can someone show me how I can modify my stateChanged method accordingly to avoid the exception?

Edit: And below is my addTab() method. This is called multiple times at the beginning of the program, and it 'sometimes' fires stateChanged() method. And at some point stateChanged() causes the exception. That's what I could tell from the debugger up to now. I know it doesn't seem clear, so if you haven't already heard this kind of thing before, that's OK, thanks for your effort. But I think this could be related to the link I gave above.

void addTab(EJournal eJournalModel,int index, String pageName) {
    SectionPage newPage = new SectionPage(jTabbedPane.getSize(), controller, eJournalModel.getSections().get(currentPageIndex));
    JScrollPane scrollPane = new JScrollPane(newPage);
    scrollPanes.add(index, scrollPane);
    sectionPages.add(index, newPage);
    jTabbedPane.insertTab(pageName, idleIcon, scrollPane, null, index);
    jTabbedPane.updateUI();
}

Edit2 : This exception is thrown. After my methods actually finished executing and evertying is finished, an actionPerformed() is fired, then a whole bunch of stuff and then exception.

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0
        at javax.swing.plaf.basic.BasicTabbedPaneUI.tabForCoordinate(BasicTabbedPaneUI.java:1488)
        at javax.swing.plaf.basic.BasicTabbedPaneUI.setRolloverTab(BasicTabbedPaneUI.java:558)
        at javax.swing.plaf.basic.BasicTabbedPaneUI.access$2000(BasicTabbedPaneUI.java:37)
        at javax.swing.plaf.basic.BasicTabbedPaneUI$Handler.mouseEntered(BasicTabbedPaneUI.java:3604)
        at java.awt.Component.processMouseEvent(Component.java:6272)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3255)
        at java.awt.Component.processEvent(Component.java:6028)
        at java.awt.Container.processEvent(Container.java:2041)
        at java.awt.Component.dispatchEventImpl(Component.java:4630)
        at java.awt.Container.dispatchEventImpl(Container.java:2099)
        at java.awt.Component.dispatchEvent(Component.java:4460)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574)
        at java.awt.LightweightDispatcher.trackMouseEnterExit(Container.java:4363)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4220)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
        at java.awt.Container.dispatchEventImpl(Container.java:2085)
        at java.awt.Window.dispatchEventImpl(Window.java:2475)
        at java.awt.Component.dispatchEvent(Component.java:4460)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
+2  A: 

I'd recommend firing up a debugger and stepping through your code until you reach the point where the exception is thrown. See what value is causing this and start working backwards.

It's possible to tell from the three lines of code that you've posted. Is

currentPageIndex = jTabbedPane.getSelectedIndex();

a data member of your Listener implementation?

What's the value of the index that you're passing in?

duffymo
thanks, I'm stepping but I really lost track of the events :) it just keeps jumping through the API, where everything is supposed to end.
Halo
Maybe you need a ChangeListener just for the tabs that you can trigger easily.
duffymo
At the beginning of the program I create and add my three panels to the JTabbedPane. And after the calling method actually finishes, some dispatching events are fired, processMouse Event and.. let me write the exception stuff to the question.
Halo
So actually this exception does not crash my work, but throws a weird exception afterwards.
Halo
A: 

You did not post a SSCCE. 5 lines of code is NOT a SSCCE.

For one thing you should NOT be using the updateUI() method. I have no idea why I see this so often in posted code.

camickr
I shouldn't use updateUI()? what should I use?
Halo
I removed updateUI() and it doesn't throw an exception now.
Halo
So is the question answered. Just wondering because you haven't accepted any answer yet?
camickr
I would say because your answer is a bit aggressive and lacks any explanation. Complaining that you see updateUI() everywhere doesn't help explaining why he shouldn't use it.
Gnoupi
I will, geez, calm down. I know how to accept, look at my rate.
Halo
@gnoupi, The API explains what the method is used for. I should not have to spend time repeating information found in the API. My time can be better spent helping other people. Posters need to learn to read the API to understand how methods are used before blindly copying code. How much time was spent by halo and the people who answered this question simply because the API wasn't read the first time the poster tried to use this method?
camickr
If you don't want to spend time explaining something, nobody forces you. I understand your point, but it doesn't make your answer any less incomplete. 60% of questions on a site like this can be answered by "search on Google" or "read the manual". But what makes this site different is that you have people who like to spend time explaining things, and get "rewarded" by reputation for that. If you prefer to explain something else, nobody forces you to answer in the first place. But a better explained answer gets my (and others) votes, that's all. The RTFM attitude is wrong on this site.
Gnoupi
I would rather give the proper answer than give an explanation that does not solve the problem. You seemed to like Devons answer even though it had nothing to do with the problem. Swing events already execute on the EDT. The potential issue was the "ordering of events" which is why the invokeLater was mentioned as a possible solution. RTFM is the proper attitude an any site. "If you give someone a fish they eat for a day. Teach someone to fish and they eat for life". I prefer to teach, not spoon feed. The API explains it better than I can. Follow up questions can be asked "after" reading it.
camickr
+2  A: 

The most likely answer is you are altering something in Swing from a non-EDT thread. Anything that touches a Swing component, or a model used by a Swing component must execute on the EDT. This includes construction of Swing objects and models.

The hands-down easiest way to find these sort of non-EDT actions is to run with the Substance Look and Feel. Go to the Substance web site and click "Get". Download the Substance and Trident libraries, add them to your classpath, then start your JVM with the option

-Dswing.defaultlaf=org.pushingpixels.substance.api.skin.SubstanceBusinessLookAndFeel

Substance is very adamant that swing actions take place on the EDT. It will throw an exception if you do something another thread. Best part is that since the exception occurs before any event is dispatched the offending code is still on the stack. This lets you where the error really happened instead trying to backtrack through multiple pumpEvent stacks.

Note: Substance is not a replacement for careful coding. There are cases where it can fail to detect non-EDT changes to models. Substance just makes it easier.

Devon_C_Miller
Thank you for an answer which explains the problem, and is not only condescending like another one. Such exceptions indeed most like happen from a situation of concurrent modification on a Swing component. (Changing something on a Swing component on another thread than the EDT is indeed likely to create problems if the EDT triggers a repaint at the same moment. Also, thanks for the Substance link, didn't know about that one.
Gnoupi
thanks man, and also for the link.
Halo