Java Swing BasicUI更新错误,我该怎么办?

时间:2009-06-25 19:35:08

标签: java multithreading swing swingworker

我的程序使用Swing JPanel,JList,JScrollPane ...

它运行正常,但生成了以下错误消息,但在消息中它没有说我的程序的哪一行导致错误,我该怎么办?

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

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)

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

我的程序中有各种.validate()和.repaint()语句,以确保它正确运行。因为我的程序看起来很好,这是否意味着我可以忽略错误?我能做些什么来避免错误信息?

=============================================== ====================================== 这里有更多细节:
&LT 1为卤素; Java版jdk1.6.0_11
&LT 2 - ;我如何创建列表:

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是对的,因为我的程序需要初始化很长的列表,这需要大约一分钟。我迫不及待地想在init完成之前看到UI,所以我把它放在一个“SwingWorker”类中,让它在app UI窗口打开后执行init;这样我就可以从UI中看到进度,而不是等待第一个窗口打开。在我看来,PC的缓慢导致UI更新过程变得混乱;如果我后来搬到更快的机器上,Swing应该把它弄清楚,或者我对此是对的吗?

我尝试使用“(包装Runnable中的更改并调用SwingUtilities.invokeLater)”方法,但它没有像我预期的那样工作。等待所有列表填写完毕,然后打开第一个窗口;这意味着我必须在第一个UI显示之前查看空屏幕一分钟。

使用SwingWorker,它现在会随机显示错误消息 - 有时在这里,有时在那里,有时则根本不显示。

我的SwingWorker看起来像这样:

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); }
}

5 个答案:

答案 0 :(得分:4)

我认为Yishai是对的。我有类似的行为并将其包装成... EventQueue.invokeLater ...解决了我的问题。

java.awt.EventQueue.invokeLater(new Runnable() {
    @Override
        public void run() {
            listModel.addElement(book);
            jListBooks = new JList(listModel);
            jListBooks.setCellRenderer(new RobotBookListRenderer());
            jScrollPane1.setViewportView(jListBooks);
            jListBooks.updateUI();
        }
    });

答案 1 :(得分:3)

这里值得关注的一个明显原因是您在不同的线程中修改模型,而不是在Swing事件队列中。如果是这种情况,那么您的代码确实存在问题(将更改包装在Runnable中,如果没有别的话,请调用SwingUtilities.invokeLater)。

如果没有,我肯定会看到你只看到一个摆动错误的情况,并且不值得让你的应用程序崩溃。但鉴于此堆栈跟踪的性质,我认为不太可能,更可能的原因是线程和事件队列。)

答案 2 :(得分:2)

我猜这个例外也是因为并发修改了一些swing对象数组。

SwingWorker可以选择“进行中的事件”。您需要覆盖process(List<V> chunks)受保护的方法,并使用void publish(V... chunks)方法将状态更新发送到UI。在您的处理案例中,这意味着定期提交您的部分结果,这样用户就不会觉得无聊。

答案 3 :(得分:0)

您是如何设置数据模型的? UI组件被告知您在dataModel中至少有4个项目,但模型没有那么多。

答案 4 :(得分:0)

我遇到了这个问题,并且发现了:

  • 如果您有JList对象
  • 致电时:listModel.removeAllElements()
  • 然后将元素添加到listModel
有时候呢?执行valueChanged事件。

这可能是随机的。我的代码是在SwingWorker中执行的。 解决方案不是调用removeAllElements而是创建一个新的ListModel。

不要这样做:

DefaultListModel listModel =(DefaultListModel)myJList.getModel(); listModel.removeAllElements();

这样做:

DefaultListModel listModel = new DefaultListModel(); myJList.setModel(ListModel的);

此代码?有时?执行valueChanged方法:

listModel.addElement(符号);