Java swing 选项卡式窗格添加选项卡异常

Java swing tabbed pane add tab exception

我有一个 Java swing 应用程序,它创建并显示一个选项卡式窗格并创建一个更新线程。触发时的更新线程需要添加一组包含内容的选项卡,但我时常遇到异常 "Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException"。

这与在不同线程中添加选项卡有关吗?如果是这样,我该如何以线程安全的方式向它添加一个选项卡??

这是一个说明问题的示例应用程序

public class Example extends JFrame implements Runnable {

    private final JTabbedPane tabbedPane;
    private final Rectangle bounds;

    public Example() {
        super("Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        bounds = new Rectangle(0, 0, 500, 500);
        setBounds(bounds);
        setLayout(null);

        tabbedPane = new JTabbedPane();
        tabbedPane.setBounds(bounds);

        JPanel jp = new JPanel();
        jp.setLayout(null);
        jp.setBounds(bounds);
        jp.add(tabbedPane);
        add(jp);

        new Thread(this).start();
    }

    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < 3; i++) {
                tabbedPane.addTab("NEW" + i, new JPanel());
                repaint();
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static void main(String[] args) {
        Example e = new Example();
        e.setVisible(true);
    }
}

Swing 不是线程安全的...

这意味着您永远不应尝试从事件调度线程的上下文之外创建或修改 UI。

可能的问题是您 运行 进入了某种竞争状态。查看Concurrency in Swing and How to use Swing Timers了解更多详情

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.Timer;

public class Example extends JFrame {

    private final JTabbedPane tabbedPane;
    private final Rectangle bounds;

    public Example() {
        super("Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        bounds = new Rectangle(0, 0, 500, 500);
        setBounds(bounds);
//      setLayout(null);

        tabbedPane = new JTabbedPane();
        tabbedPane.setBounds(bounds);

//      JPanel jp = new JPanel();
//      jp.setLayout(null);
//      jp.setBounds(bounds);
//      jp.add(tabbedPane);
//      add(jp);

        add(tabbedPane);

        Timer timer = new Timer(50, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (int i = 0; i < 3; i++) {
                    tabbedPane.addTab("NEW" + tabbedPane.getTabCount(), new JPanel());
                }
                tabbedPane.revalidate();
            }
        });
        timer.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                Example e = new Example();
                e.setVisible(true);
            }
        });
    }
}

避免使用 null 布局,像素完美布局是现代 ui 设计中的一种错觉。影响组件个体大小的因素太多,none 是您可以控制的。 Swing 旨在与核心的布局管理器一起工作,丢弃这些将导致无穷无尽的问题和问题,您将花费越来越多的时间来尝试纠正

查看 Laying Out Components Within a Container 了解更多详情