我有以下SSCCE,需要JTabbedPane
,并添加500个包含CustomJPanel
的标签。请注意,组件CustomJPanel
是" long"生成,因为我(故意)向其添加100 JLabel
。
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class Class1 {
public static void main(String[] args) {
JFrame window = new JFrame();
window.setTitle("Parent frame");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(1200, 800);
window.setLocationRelativeTo(null);
window.setVisible(true);
JTabbedPane jtp = new JTabbedPane();
window.add(jtp);
//new Thread(new Runnable() {
// public void run() {
for (int i = 0; i < 500; i++) {
jtp.addTab("tab"+i, new CustomJPanel());
}
// }
//}).start();
}
}
class CustomJPanel extends JPanel {
public CustomJPanel() {
for (int i = 0; i < 100; i++) {
this.add(new JLabel("test"));
}
}
}
当我运行此代码时,我很有可能获得以下异常:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0
at javax.swing.plaf.basic.BasicTabbedPaneUI.tabForCoordinate(Unknown Source)
at javax.swing.plaf.basic.BasicTabbedPaneUI.setRolloverTab(Unknown Source)
at javax.swing.plaf.basic.BasicTabbedPaneUI.access$2100(Unknown Source)
at javax.swing.plaf.basic.BasicTabbedPaneUI$Handler.mouseEntered(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEnterExit(Unknown Source)
at java.awt.LightweightDispatcher.trackMouseEnterExit(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
当我在JTabbedPane
中快速添加需要很长时间才能生成的组件时,会导致此问题。如果我删除CustomJPanel
中的for循环,使其只保留一个JLabel
,则不会发生异常。请注意,虽然在此示例中,异常始终为&#34; 0&#34;,但在我的应用中,它可以是任意数字。
如果在单独的线程中添加选项卡,则异常似乎发生的可能性更高。
我发现降低获得此异常的可能性的唯一方法是在添加每个选项卡之间添加几十毫秒的延迟(Thread.Sleep()
)。但是,它仍然会不时发生。
有没有办法阻止此异常发生,或阻止它在控制台中显示?请注意,我无法抓住它,因为它并没有指向我的代码中的任何内容,它是所有&#34;未知来源&#34;。
修改:我已将Class1
的代码更改为在EDT上运行:
public class Class1 {
public static JFrame window;
public static JTabbedPane jtp;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
window = new JFrame();
window.setTitle("Parent frame");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(1200, 800);
window.setLocationRelativeTo(null);
window.setVisible(true);
jtp = new JTabbedPane();
window.add(jtp);
new SwingWorker<Void, Void>() {
@Override
public Void doInBackground() {
for (int i = 0; i < 500; i++) {
jtp.addTab("tab"+i, new CustomJPanel());
}
return null;
}
@Override
public void done() {}
}.execute();
}
});
}
}
然而,异常仍然发生。我有什么问题吗?
答案 0 :(得分:1)
您错误地使用了doInBackground()
。当你在背景中&#34;&#34;你不在美国东部时间。因此,调用UI的addTab()
调用是禁止的。
要正确使用SwingWorker
,您必须publish()
中间结果。 process()
方法在EDT上下文中接收已发布的结果,可以安全地修改UI。
public class Class1 {
public static void main(String[] args) {
SwingUtilities.invokeLater(Class1::new);
}
Class1() {
JFrame window = new JFrame();
window.setTitle("Parent frame");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(1200, 800);
window.setLocationRelativeTo(null);
JTabbedPane jtp = new JTabbedPane();
window.add(jtp);
window.setVisible(true);
new Builder(jtp).execute();
}
}
class Builder extends SwingWorker<Void, CustomJPanel> {
JTabbedPane jtp;
Builder(JTabbedPane _jtp) {
jtp = _jtp;
}
@Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < 500; i++) {
CustomJPanel panel = new CustomJPanel();
publish(panel);
}
return null;
}
@Override
protected void process(List<CustomJPanel> panels) {
int i = jtp.getTabCount();
for (CustomJPanel panel : panels) {
jtp.addTab("tab" + i, panel);
i++;
}
}
}
注意:创建CustomJPanel extends JPanel
可能看起来像是在操纵UI,但实际上并非如此。 JPanel
尚未实现。只有将JPanel
添加到已实现的UI项目(例如JTabbedPane
)时,才能真正实现。因此,我们实际上可以安全地创建JPanel
,并在工作线程中使用JLabel
个孩子等。但它无法添加到工作线程中已实现的UI项目中。