【问题标题】:Exception thrown while working with JTabbedPane使用 JTabbedPane 时抛出异常
【发布时间】:2010-05-01 20:53:48
【问题描述】:

我在我的应用程序中使用了一个 JTabbedPane,我用ChangeListener 监听它的变化,这样我就可以知道当前选择了哪个选项卡。 所以我的stateChanged 方法是;

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

但是当我向JTabbedPane 添加新标签时,它会在上述方法中抛出ArrayIndexOutOfBoundsException,我不知道为什么。对于类似的情况,有人建议这是一个错误http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4873983,但正如您将看到的那样,解决方案是使用 EventDispatchThread 中的 Swing。

这是什么意思,它们是指SwingUtilities.invokeLater 吗?有人可以告诉我如何相应地修改我的stateChanged 方法以避免异常吗?

编辑:下面是我的addTab() 方法。这在程序开始时被多次调用,它“有时”会触发stateChanged() 方法。在某些时候stateChanged() 会导致异常。这就是我从调试器到现在所能知道的。我知道这似乎不太清楚,所以如果您以前没有听说过这种事情,那没关系,感谢您的努力。但我认为这可能与我上面给出的链接有关。

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 : 抛出此异常。在我的方法实际执行完毕并且evertying完成后,actionPerformed() 被触发,然后是一大堆东西,然后是异常。

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)

【问题讨论】:

  • 如果建议尝试使用 SwingUtilities.invokeLater,那么您为什么不先尝试呢?如果效果很好。如果没有,那么我们将知道不再建议它。如果您以前从未使用过此方法,请在论坛或网络上搜索示例。如果您仍有问题,请发布您的 SSCCE:sscce.org

标签: java swing exception jtabbedpane


【解决方案1】:

最可能的答案是您正在从非 EDT 线程更改 Swing 中的某些内容。任何触及 Swing 组件或 Swing 组件使用的模型必须在 EDT 上执行。这包括构建 Swing 对象和模型。

找到这类非 EDT 操作的最简单的方法是使用 Substance 外观运行。转到Substance web site 并单击“获取”。下载 Substance 和 Trident 库,将它们添加到类路径中,然后使用选项启动 JVM

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

Substance 非常坚持认为挥杆动作发生在 EDT。如果您在另一个线程中执行某些操作,它将引发异常。最好的部分是,由于异常发生在任何事件被调度之前,有问题的代码仍然在堆栈上。这让您可以尝试在多个 pumpEvent 堆栈中回溯错误真正发生的位置。

注意: Substance 不能替代仔细编码。在某些情况下,它可能无法检测到模型的非 EDT 更改。物质只是让它更容易。

【讨论】:

  • 感谢您的回答,它解释了问题,而不仅仅是像另一个人那样居高临下。此类异常确实很可能发生在 Swing 组件的并发修改的情况下。 (如果 EDT 在同一时刻触发重绘,那么在 EDT 之外的另一个线程上更改 Swing 组件上的某些内容确实可能会产生问题。另外,感谢 Substance 链接,不知道那个。
【解决方案2】:

我建议您启动一个调试器并单步执行您的代码,直到您到达引发异常的地步。看看是什么值导致了这种情况并开始向后工作。

从您发布的三行代码中可以看出。是

currentPageIndex = jTabbedPane.getSelectedIndex();

Listener 实现的数据成员?

您传入的index 的值是多少?

【讨论】:

  • 谢谢,我正在迈步,但我真的忘记了事件:) 它只是不断地跳过 API,一切都应该结束。
  • 也许您只需要一个 ChangeListener 来处理可以轻松触发的选项卡。
  • 在程序开始时,我创建了三个面板并将其添加到 JTabbedPane。在调用方法实际完成后,会触发一些调度事件,processMouse 事件和.. 让我将异常内容写到问题中。
  • 所以实际上这个异常并没有使我的工作崩溃,而是在之后抛出一个奇怪的异常。
【解决方案3】:

您没有发布 SSCCE。 5 行代码不是 SSCCE。

一方面,您不应该使用 updateUI() 方法。我不知道为什么我在发布的代码中经常看到这种情况。

【讨论】:

  • 我会说,因为你的回答有点激进,缺乏任何解释。抱怨你到处都能看到 updateUI() 无助于解释他为什么不应该使用它。
  • @gnoupi,API 解释了该方法的用途。我不应该花时间重复在 API 中找到的信息。我的时间可以更好地用于帮助他人。发帖者需要先学会阅读API,了解方法是如何使用的,然后再盲目复制代码。光环和回答这个问题的人仅仅因为发布者第一次尝试使用这种方法时没有阅读 API 而花费了多少时间?
  • 如果你不想花时间解释某事,没有人强迫你。我理解您的观点,但这并没有使您的答案变得不完整。此类网站上 60% 的问题可以通过“在 Google 上搜索”或“阅读手册”来回答。但这个网站的不同之处在于,你有喜欢花时间解释事情的人,并因此获得声誉“奖励”。如果您更愿意解释其他内容,那么没有人会强迫您首先回答。但是一个更好解释的答案会得到我(和其他人)的选票,仅此而已。此站点上的 RTFM 态度是错误的。
  • 我宁愿给出正确的答案,也不愿给出不能解决问题的解释。您似乎喜欢 Devons 的回答,即使它与问题无关。 Swing 事件已在 EDT 上执行。潜在的问题是“事件的顺序”,这就是为什么将 invokeLater 作为可能的解决方案提到的原因。 RTFM 是任何网站的正确态度。 “如果你给某人一条鱼,他们可以吃一天。教某人钓鱼,他们会吃一辈子”。我更喜欢教书,而不是勺子喂食。 API 比我能解释得更好。阅读后可以提出后续问题。
  • 有了java GUI库,做SSCCE真的很难。它们迫使您调用更多函数并创建比普通 SO 问题更多的对象。
猜你喜欢
  • 2013-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-24
  • 2014-03-26
  • 1970-01-01
  • 2013-05-10
相关资源
最近更新 更多