Frank Frank - 1 month ago 8
Java Question

Java Swing BasicUI update error, what can I do?

My program uses Swing JPanel, JList, JScrollPane ...

It runs fine, but generated the following error message, and yet in the message it didn't say which line of my program caused the error, what can I do ?

=========================================================================

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 3

at javax.swing.plaf.basic.BasicListUI.updateLayoutState(BasicListUI.java:1356)
at javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState(BasicListUI.java:1299)
at javax.swing.plaf.basic.BasicListUI.getPreferredSize(BasicListUI.java:566)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1632)
at javax.swing.ScrollPaneLayout.layoutContainer(ScrollPaneLayout.java:769)
at java.awt.Container.layout(Container.java:1398)
at java.awt.Container.doLayout(Container.java:1387)
at java.awt.Container.validateTree(Container.java:1485)
at java.awt.Container.validate(Container.java:1457)
at javax.swing.RepaintManager.validateInvalidComponents(RepaintManager.java:670)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:127)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
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)


=====================================================================================

I do have various .validate() and .repaint() statements in my program to make sure it runs correctly. Because my program looks fine, does that mean I can ignore the error ? Anything I can do to avoid the error message ?

=====================================================================================
Here is more details:

<1> Java version jdk1.6.0_11

<2> How I init the list:

for (int Selector_Id=0;Selector_Id<6;Selector_Id++)
{
Stock_Symbol_Data[Selector_Id]=new DefaultListModel();
Stock_Symbol_List[Selector_Id]=new JList(Stock_Symbol_Data[Selector_Id]);
Stock_Symbol_ScrollPane[Selector_Id]=new JScrollPane(Stock_Symbol_List[Selector_Id]);
}
...
Stock_Symbol_Data[A_Selector_Id].clear();

if (Selected_Symbols_Vector.size()>0)
for (int i=0;i<Selected_Symbols_Vector.size();i++)
Stock_Symbol_Data[A_Selector_Id].addElement(Selected_Symbols_Vector.elementAt(i));


Yishai is right, since my program needs to init a very long list, which requires about a minute. I can't wait to see the UI before the init is finished, so I put it in a "SwingWorker" class and let it do the init after the app UI window opens; that way I can see the progress from within the UI rather then wait for the first window to open. It seems to me it's the PC's slowness that's messing up the UI update process; if I later on move to a faster machine, Swing should straighten this out, or am I right about this?

I tried to use the "(wrap the change in a Runnable and call SwingUtilities.invokeLater)" approach, but it didn't work as I expected. It waits till all the list is filled in, then opens the first window; that means I have to look at empty screen for one minute before the first UI shows up.

With SwingWorker, it now shows the error message randomly--sometimes here, sometimes there, other times not at all.

My SwingWorker looks like this :

class Update_Selection_Worker extends SwingWorker<Integer,Integer> // Look into SwingWorkerDemo in Fit for details
{
int Selector_Id;
boolean Update_Only_This_Selector;
Stock_Image_Scanner Stock_image_scanner;

public Update_Selection_Worker(int Selector_Id,boolean Update_Only_This_Selector,Stock_Image_Scanner Stock_image_scanner)
{
this.Selector_Id=Selector_Id;
this.Update_Only_This_Selector=Update_Only_This_Selector;
this.Stock_image_scanner=Stock_image_scanner;
}

@Override
protected Integer doInBackground() throws Exception
{
// Out(" In Update_Selection_Worker Selector_Id="+Selector_Id);

if (Update_Only_This_Selector) // Only need to update from Rules_Panel_Id, eariler ones haven't changed
{
Stock_image_scanner.Update_Selector_List(Selector_Id);
Thread.sleep(5);
publish(Selector_Id);
}
else for (int i=Selector_Id;i<Stock_image_scanner.Rules_Panel_Count;i++)
{
Stock_image_scanner.Update_Selector_List(i);
Thread.sleep(5);
publish(i);
}

return 1;
}

@Override
protected void process(java.util.List<Integer> chunks) // As the worker thread executes, it can publish results of V type. Override the process method to work with intermediate results.
{
for (final int i : chunks)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{

Stock_image_scanner.Selector_Total_Label[i].setText(Stock_image_scanner.Stock_Symbol_Data[i].getSize()+"");
Stock_image_scanner.Stock_Symbol_List[i].revalidate();
Stock_image_scanner.Stock_Symbol_List[i].repaint();
Stock_image_scanner.Stock_Symbol_ScrollPane[i].revalidate();
Stock_image_scanner.Stock_Symbol_ScrollPane[i].repaint();
Stock_image_scanner.Selector_Panel[i].revalidate();
Stock_image_scanner.Selector_Panel[i].repaint();

}
});
}
}

@Override
protected void done()
{
}

public static void out(String message) { System.out.print(message); }
public static void Out(String message) { System.out.println(message); }
}

Answer

I guess too the exception is because the concurrent modification of some swing object array.

SwingWorker has the option for 'in progress events'. You need to override process(List<V> chunks) protected method and use the void publish(V... chunks) method to send status update to the UI. In your processing case this means submit your partial results periodically so the user doesn't get bored.

Comments