不能在 actionlistener 的 JFrame 上使用 add 方法

Cannot use add method on JFrame in actionlistener

我正在做一个学校项目,但我被卡住了。单击 JMenuItem 后,我试图在侦听器中创建面板(在 JFrame 上简单添加方法),但它不起作用。如果我尝试在侦听器外部创建面板,它在 no.bud 内部工作得很好。 Panel 只是 JPanel 的扩展,目前没有任何功能,但将来计划在其中添加一些功能。

public class Gui implements GuiConstants, ActionListener {
    public static final int INIT_WIDTH = 1024;
    public static final int INIT_HEIGHT = 560;

    private JFrame frame;
    private KPanel KPanels[];
    private GridBagConstraints gbc;

    public Gui() {
        KPanels = new KPanel[4];
        this.gbc = new GridBagConstraints();
    }

    /**
     * Vytváří okno aplikace + inicializuje toolbar
     */
    public void createWindow() {
        frame = new JFrame(Strings.get("window-title"));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle(Strings.get("window-title"));

        frame.setJMenuBar(new KToolbar());
        frame.pack();
        frame.setSize(Gui.INIT_WIDTH, Gui.INIT_HEIGHT);
        frame.setVisible(true);
        frame.setLayout(new GridBagLayout());
        addToolbarListener(this);
        createPanel(1);
    }

    /**
     * Nastaví listener pro toolbar akce (kliknutí)
     * @param listener
     */
    public void addToolbarListener(ActionListener listener) {
        ((KToolbar) frame.getJMenuBar()).addActionListener(listener);
    }

    public void disableToolbarItem(int itemId) {
        ((KToolbar) frame.getJMenuBar()).disable(itemId);
    }

    public KPanel createPanel(int i) {
        return this.createPanel(i, null);
    }

    /**
     * Vytvoří i-tý panel v případě, že ještě neexistuje a i je v rozsahu 0-3 včetně
     * @param i
     * @return
     */
    public KPanel createPanel(int i, Color color){
        if (i > 3 || i < 0 || KPanels[i] != null) {
            return null;
        }

        this.KPanels[i] = new KPanel();
        if (color != null)
            this.KPanels[i].setBackground(color);
        this.gbc.fill = GridBagConstraints.BOTH;
        this.gbc.weightx = 1;
        this.gbc.weighty = 1;
        this.gbc.gridx = i % 2;
        this.gbc.gridy = i / 2;
        this.frame.add(this.KPanels[i], this.gbc);
        return this.KPanels[i];
    }

    /**
     * Odstraní t-tý panel v případě, že existuje a i je v rozsahu 0-3 včetně.
     * @param i
     * @return
     */
    public boolean removePanel(int i) {
        if (i > 3 || i < 0 || KPanels[i] == null) {
            return false;
        }

        this.frame.remove(this.KPanels[i]);
        this.KPanels[i] = null;
        return true;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        createPanel(2, Color.CYAN);
    }
}

public class KMenuItem extends JMenuItem {
    private int id;

    KMenuItem(String name, int id) {
        super(name);
        this.id = id;
    }

    public int getId() {
        return id;
    }
}

public class KToolbar extends JMenuBar{
    ArrayList<KMenuItem> KMenuItems;

    KToolbar() {
        super();
        KMenuItems = new ArrayList<>();
        generateMenu();
    }

    public void addActionListener(ActionListener listener) {
        for (KMenuItem item : KMenuItems) {
            item.addActionListener(listener);
        }
    }

    public void disable(int id) {
        for (KMenuItem mi : KMenuItems) {
            if (mi.getId() == id)
                mi.setEnabled(false);
        }
    }

    public void enable(int id) {
        for (KMenuItem mi : KMenuItems) {
            if (mi.getId() == id)
                mi.setEnabled(true);
        }
    }

    private KMenuItem getLast() {
        return KMenuItems.get(KMenuItems.size() - 1);
    }

    private void generateMenu() {
        JMenu game = new JMenu(Strings.get("game"));
        KMenuItems.add(new KMenuItem(Strings.get("button-exit"), Gui.EXIT));
        game.add(getLast());

        JMenu newGame = new JMenu(Strings.get("button-new-game"));
        KMenuItems.add(new KMenuItem(Strings.get("button-new-game-current"), Gui.NEW_GAME_CURRENT));
        newGame.add(getLast());
        KMenuItems.add(new KMenuItem(Strings.get("button-new-game-panel"), Gui.NEW_GAME_PANEL));
        newGame.add(getLast());
        game.add(newGame);

        KMenuItems.add(new KMenuItem(Strings.get("button-save"), Gui.SAVE));
        game.add(getLast());
        KMenuItems.add(new KMenuItem(Strings.get("button-load"), Gui.LOAD));
        game.add(getLast());
        KMenuItems.add(new KMenuItem(Strings.get("button-abort-game"), Gui.ABORT_GAME));
        game.add(getLast());

        add(game);
    }

}

public class KPanel extends JPanel {
}

public interface GuiConstants {

    // System
    public static final int EXIT = 1;
    public static final int SAVE = 2;
    public static final int LOAD = 3;

    // Language
    public static final int CHANGE_LANG = 4;

    // Game
    public static final int NEW_GAME_PANEL = 5;
    public static final int NEW_GAME_CURRENT = 6;
    public static final int UNDO_GAME = 7;
    public static final int REDO_GAME = 8;
    public static final int ABORT_GAME = 9;
    public static final int HINT_GAME = 10;
}

public class Main {

    private Gui GUI;

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Main();
            }
        });
    }

    Main() {
        GUI = new Gui();
        GUI.createWindow();
    }
}

编辑:添加了完整示例。没有错误日志。我什至检查了对象引用,一切都合适。它只是不会以某种方式添加到框架中,我不知道为什么。

我自己解决了。我忘了用每个 frame.add 调用 frame.revalidate() (在 createPanel 方法中)。