【问题标题】:Swing JTabbedPane throws IndexOutOfBoundsException while filling upSwing JTabbedPane 在填满时抛出 IndexOutOfBoundsException
【发布时间】:2012-07-20 12:38:14
【问题描述】:

我有一个包含多个组件的应用程序。其中一个是JTabbedPane,里面有其他东西(很明显)。我通过这个getter访问这个面板:

public JTabbedPane getPlotTabbedPane() {
    if (plotTabs == null) {
        plotTabs = new JTabbedPane();
        plotTabs.setFocusable(false);

        plotTabs.add("Measurement", getPlotPanel());
        plotTabs.add("Time", getPlotPanel().getTimePanel());
        plotTabs.add("Data", getPlotPanel().getDataPanel());
        plotTabs.add("Statistics", getPlotPanel().getStatisticsPanel());
        plotTabs.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                getPlotPanel().refreshRenderer();
            }
        });
    }
    return plotTabs;
}

所以第一次,我访问它(即当它尚未创建时),我创建它,其他时候,我只是返回已经创建的JTabbedPane。我已经被告知这不是最好的技术(如果有人可以告诉我一个不会弄乱布局组合代码的更好的技术,我非常愿意接受建议)。

现在,这在 99% 的情况下(应用程序启动)都可以正常工作。在 1% 中,我得到一个

Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.Vector.elementAt(Vector.java:430)
    at javax.swing.JTabbedPane.getTitleAt(JTabbedPane.java:1091)
    at javax.swing.plaf.basic.BasicTabbedPaneUI$Handler.updateHtmlViews(BasicTabbedPaneUI.java:3564)
    at javax.swing.plaf.basic.BasicTabbedPaneUI$Handler.componentAdded(BasicTabbedPaneUI.java:3699)
    at java.awt.Container.processContainerEvent(Container.java:2065)
    at java.awt.Container.processEvent(Container.java:2036)
    at java.awt.Component.dispatchEventImpl(Component.java:4653)
    at java.awt.Container.dispatchEventImpl(Container.java:2097)
    at java.awt.Component.dispatchEvent(Component.java:4481)
    at java.awt.Container.addImpl(Container.java:1083)
    at javax.swing.JTabbedPane.insertTab(JTabbedPane.java:703)
    at javax.swing.JTabbedPane.addTab(JTabbedPane.java:777)
    at javax.swing.JTabbedPane.add(JTabbedPane.java:814)
    at companyname.product.gui.Tab.getPlotTabbedPane(Tab.java:386)
    at companyname.product.gui.Tab.getFullPlotPanel(Tab.java:374)
    at companyname.product.gui.Tab.initComponents(Tab.java:262)
    at companyname.product.gui.Tab.<init>(Tab.java:80)

我不会在堆栈中进一步深入,但这基本上是 GUI 的创建。 Tab 是扩展的 JPanel。我无法真正弄清楚,问题出在哪里,我能做些什么来防止它。显然,我可以将 Tab.java 的第 386 行包装在 try/catch 中,但这并不能解决问题,它只是解决了症状......

那么,你知道问题出在哪里,我该如何解决或者我应该怎么做?

【问题讨论】:

  • 你确定在堆栈跟踪后面没有Caused by: ...吗?
  • Tab.java 中的第 80 行是什么?
  • 您可能想尽快发布SSCCE 以获得更好的帮助。
  • 你只是在 Event Dispatch Thread 中操作你的 Swing 组件吗?
  • @AleksG 嗯...下次发生时我会看到,但我很确定,没有Caused by:,因为我会注意到这一点。 Tab.java 中的第 80 行是构造函数中的super(); 调用(调用JPanel#JPanel())。

标签: java swing exception jtabbedpane


【解决方案1】:

堆栈跟踪似乎建议您从另一个线程访问 Swing 组件,然后是事件调度线程 (EDT)。这是不允许的。

我很确定,如果您确保只从正确的线程访问 Swing 组件,您将不会再看到此异常。

更多信息可以在Concurrency in Swing 教程中找到。您还可以查看 this article,其中包含一个 RepaintManager,它可以帮助您检测 Swing 线程违规

【讨论】:

  • 如果我需要从另一个线程访问它怎么办? SwingUtilities.invokeNowAndWait()?这将广泛地炸毁我的代码。这些东西通常是怎么做的?另外:感谢RepaintManager 的链接,这很有帮助。
  • 这是可能的。但通常你根本不需要多线程访问 UI 组件
  • 我...我正在做耗时的测量,它还通过 gui 向用户提供实时反馈。我显然没有在 EDT 中进行测量,但必须以某种方式更改 GUI。同时,我必须对用户交互做出反应(根据交互,界面也会发生很大变化)。
  • 那你确实应该使用SwingUtilities中的方法,或者考虑使用SwingWorker,它允许在后台进行计算并在最后+中间更新正确的UI跨度>
  • @brimborium Swing 的黄金法则,从不,我们的意思是从不,尝试从除 ETD 之外的任何线程访问任何 UI 组件。您冒着破坏 UI 的风险(就像您在这里所做的那样)。所有耗时的处理都应该在单独的线程中完成,并且正如 robin 所建议的那样,您应该将 UI 与 SwingUtilites.invoke... 方法同步,或者利用 SwingWorker 类。查看 robin 向您推荐的教程。就是这样,对不起
猜你喜欢
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 2013-05-10
  • 2013-05-20
  • 1970-01-01
  • 2016-06-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多