将 JPanel 动态插入 TabbedPanel 时出现 ArrayIndexErrorException

ArrayIndexErrorException when inserting dynamically a JPanel into a TabbedPanel

我正在尝试实现一个以 JTabbedPane 作为主要组件的 JFrame(这是 JFrame 的唯一组件)。开始时,选项卡式面板不应包含任何选项卡。后者是在事件发生时添加的。每个选项卡都包含一个带有 BorderLayout 的 JPanel。这是我遇到一些问题的代码。实际上,在添加选项卡时,我得到了一个 ArrayIndexOutOfBoundException。我已经确定了产生错误的代码行,它发生在我将第二个元素添加到面板时。有人知道如何解决这个错误吗?我试图捕获错误,但它不起作用。这是我现在的实现:

这是主框架的代码

import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;

public class MyFrame extends JFrame {

    static JTabbedPane main;

    public MyFrame() {
        main = new JTabbedPane();
        this.add(main);
        this.setMinimumSize(new Dimension(600, 800));
        this.setVisible(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.pack();
    }

    public static JPanel addTab(String title) {
        MyPanel panel = new MyPanel();
        main.addTab(title, panel);
        return panel;
    }
}

这是选项卡式面板内面板的 class:

import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneLayout;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class MyPanel extends JPanel {
    private JPanel scrollPanel;
    private JTextArea textArea;
    private JButton button;
    public MessageTo panel;

    public MyPanel() {

        JScrollPane scrollPane = new JScrollPane(
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setLayout(new ScrollPaneLayout());
        scrollPanel = new JPanel();
        scrollPane.setViewportView(scrollPanel);
        scrollPanel.setLayout(new BoxLayout(scrollPanel, BoxLayout.Y_AXIS));

        textArea = new JTextArea();
        Border roundedBorder = new LineBorder(Color.black, 1, true);
        textArea.setBorder(roundedBorder);

        button = new JButton("Send");
        JPanel panel1 = new JPanel();
        panel1.setBorder(new EmptyBorder(0, 10, 0, 0));
        panel1.add(button);

        JPanel inner_panel = new JPanel();
        inner_panel.setLayout(new BorderLayout());
        inner_panel.add(panel1, BorderLayout.EAST);
        inner_panel.add(textArea, BorderLayout.CENTER);
        inner_panel.setBorder(new EmptyBorder(10, 10, 10, 10));

        this.setLayout(new BorderLayout());
        this.add(scrollPane, BorderLayout.CENTER);
        this.add(inner_panel, BorderLayout.SOUTH); // This line produces the error
    }
}

这是我遇到的错误:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0
at javax.swing.plaf.basic.BasicTabbedPaneUI.tabForCoordinate(BasicTabbedPaneUI.java:1506)
at javax.swing.plaf.basic.BasicTabbedPaneUI.setRolloverTab(BasicTabbedPaneUI.java:575)
at javax.swing.plaf.basic.BasicTabbedPaneUI.access00(BasicTabbedPaneUI.java:54)
at javax.swing.plaf.basic.BasicTabbedPaneUI$Handler.mouseEntered(BasicTabbedPaneUI.java:3626)
at java.awt.Component.processMouseEvent(Component.java:6525)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at java.awt.Component.processEvent(Component.java:6281)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4872)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4698)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
at java.awt.LightweightDispatcher.trackMouseEnterExit(Container.java:4620)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4474)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
at java.awt.Container.dispatchEventImpl(Container.java:2273)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4698)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:747)
at java.awt.EventQueue.access0(EventQueue.java:103)
at java.awt.EventQueue.run(EventQueue.java:706)
at java.awt.EventQueue.run(EventQueue.java:704)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue.run(EventQueue.java:720)
at java.awt.EventQueue.run(EventQueue.java:718)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:717)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

谢谢!

编辑:

这是您可以用来测试我的代码的代码:

public class Main {

    public static MyFrame frame;

    public static void main(String[] args)   {

        frame = new MyFrame();
        new Thread() {
            public void run() {
                frame.addTab("Test");
            }
        }.start();
    }

}

替换

   new Thread() {
        public void run() {
            frame.addTab("Test");
        }
    }.start();

frame.addTab("Test");

目前,您正在尝试从另一个线程修改 GUI 元素,而不是 JFrame 所在的线程。有可能在程序完成构建 window 之前到达添加选项卡的代码,因此出现错误。 Concurrency in Swing 可能是一本好书。

正如 Kiheru 所建议的,从另一个线程修改框架必须以这种方式完成:

public class Main {

    public static MyFrame frame;

    public static void main(String[] args) throws InterruptedException,
            ExecutionException, UnknownHostException, IOException {

        frame = new MyFrame();
        new Thread() {
            public void run() {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        frame.addTab("Test");
                    }
                });
                try {
                    this.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        frame.addTab("Test2");
                    }
                });
            }
        }.start();
    }
}
import javax.swing.SwingWorker;

请阅读此处...https://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html

    new SwingWorker() {
      @Override protected Void doInBackground() throws Exception {
        return null;
      } 
      @Override protected void done() {
        //PUT HERE THE CODE
        frame.addTab("Test");
        frame.addTab("Test2");
      }
    }.execute();