【问题标题】:CardLayout using JMenu sending error messagesCardLayout 使用 JMenu 发送错误消息
【发布时间】:2012-10-06 13:44:26
【问题描述】:

大家好,我想创建一个简单的程序,在其中我可以使用 menuItems 来控制每个 JPanel。例如,如果我选择 File->New,其中 New 是 JmenuItem,它将显示一个名为 newPanel 的 JPanel。此外,如果我选择 Edit->Edit,它将显示名为 editPanel 的 JPanel 以及添加到其中的对象。到目前为止,这是我构建的:

public class CardLayoutwithMenuBar extends JFrame implements ActionListener {

    private JMenuBar menu;
    private JMenu fileMenu;
    private JMenu editMenu;
    private JMenu exitMenu;

    private JMenuItem openItem;
    private JMenuItem newItem;
    private JMenuItem editItem;
    private JMenuItem exitItem;

    private JPanel newPanel;
    private JPanel openPanel;
    private JPanel editPanel;
    private JPanel exitPanel;

    static private CardLayout cardView;
    static private JPanel cardPanel;


    public CardLayoutwithMenuBar(){
        this.setVisible(true);
        this.setTitle("Controlling Different Panel Using CardLayout");
        this.setSize(400, 150);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create Menu bar and add to Frame
        menu = new JMenuBar();
        this.setJMenuBar(menu);

        fileMenu = new JMenu("File");
        editMenu = new JMenu("Edit");
        exitMenu = new JMenu("Exit");

        menu.add(fileMenu);
        menu.add(editMenu);
        menu.add(exitMenu);

        newItem = new JMenuItem("New File");
        openItem = new JMenuItem("File Open");
        editItem = new JMenuItem("Edit Entry");
        exitItem = new JMenuItem("Exit");

        fileMenu.add(newItem);
        fileMenu.add(openItem);
        editMenu.add(editItem);
        exitMenu.add(exitItem);

        //Declare object cardView and cardPanel and set layout of cardPanel to CardLayout
        cardView = new CardLayout();
        cardPanel = new JPanel();
        cardPanel.setLayout(cardView);


        //Create sub-panels that would correspond to each function in the menu item ex. newItem, openItem etc...
        newPanel = new JPanel();
        openPanel = new JPanel();
        editPanel = new JPanel();
        exitPanel = new JPanel();


        //add the sub-panels to the main cardpanel 
        cardPanel.add("New", newPanel);
        cardPanel.add("Open", openPanel);
        cardPanel.add("Edit",editPanel);
        cardPanel.add("Exit",exitPanel);

        newItem.addActionListener(this);
        openItem.addActionListener(this);
        editItem.addActionListener(this);
        exitItem.addActionListener(this);

        this.getContentPane().add(cardPanel, BorderLayout.CENTER);
    }

    public void actionPerformed(ActionEvent evt){
        String menuItemAction = evt.getActionCommand();

            if (menuItemAction.equals("New File")){
                cardView.show(newPanel, "New");
            }
            else if (menuItemAction.equals("File Open")){
                cardView.show(openPanel, "Open");
            }
            else if (menuItemAction.equals("Edit Entry")){
                cardView.show(editPanel, "Edit");
            }
            else if (menuItemAction.equals("Exit")){
                cardView.show(exitPanel, "Exit");
            }
            else{
                System.out.println("Opppsss you pressed something else");
        }
    }   
}

当我尝试运行这个程序时,我总是得到这个错误:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: wrong parent for CardLayout
    at java.awt.CardLayout.checkLayout(CardLayout.java:404)
    at java.awt.CardLayout.show(CardLayout.java:526)
    at com.JMenuSample.CardLayoutwithMenuBar.actionPerformed(CardLayoutwithMenuBar.java:132)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2012)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2335)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:404)
.... and the list goes on

谁能帮我解决这个问题?提前致谢!

【问题讨论】:

    标签: java swing awt layout-manager cardlayout


    【解决方案1】:
    • 必须对CardLayout-public void show(Container parent, String name)使用正确的方法

    • 然后使用cardView.show(cardPanel, "New");(insted of cardView.show(newPanel, "New");)

    • newPanel as Container 的其余部分保留并仅更改第二个。 String 形式的参数

    【讨论】:

    • 嗨,非常感谢 mKorbel 的工作!我对 GUI/Swing 还很陌生,我想我还有很多东西要学。
    【解决方案2】:

    +1 给 mKorbel(击败我)

    但是这里是:

    • 在创建JFrame 之前不要调用setVisible
    • 不要使用 setSize 而是找到合适的 LayoutManager 或覆盖 getPreferredSizeJComponent
    • JFrame 实例上调用pack()
    • Strings(来自 java 7)上使用 switch 块而不是 if 语句,因为它更有效
    • 不要不必要地 extend JFrame

    错误原因在这里:

      if (menuItemAction.equals("New File")){
                    cardView.show(newPanel, "New");
                }
                else if (menuItemAction.equals("File Open")){
                    cardView.show(openPanel, "Open");
                }
                else if (menuItemAction.equals("Edit Entry")){
                    cardView.show(editPanel, "Edit");
                }
                else if (menuItemAction.equals("Exit")){
                    cardView.show(exitPanel, "Exit");
                }
                else{
                    System.out.println("Opppsss you pressed something else");
            }
    

    您的父母是您的cardPanel,而不是您要显示的面板,由字符串参数给出:

    cardView.show(cardPanel, "New");
    

    请参阅下面的更改代码:

    import java.awt.BorderLayout;
    import java.awt.CardLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class CardLayoutWithMenuBar implements ActionListener {
    
        private JMenuBar menu;
        private JMenu fileMenu;
        private JMenu editMenu;
        private JMenu exitMenu;
        private JMenuItem openItem;
        private JMenuItem newItem;
        private JMenuItem editItem;
        private JMenuItem exitItem;
        private JPanel newPanel;
        private JPanel openPanel;
        private JPanel editPanel;
        private JPanel exitPanel;
        private CardLayout cardView;
        private JPanel cardPanel;
    
        public CardLayoutWithMenuBar() {
            JFrame frame = new JFrame();
            frame.setTitle("Controlling Different Panel Using CardLayout");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            initComponents(frame);
    
            frame.pack();
            frame.setVisible(true);
        }
    
        @Override
        public void actionPerformed(ActionEvent evt) {
    
            String menuItemAction = evt.getActionCommand();
    
            switch (menuItemAction) {
                case "New File":
                    cardView.show(cardPanel, "New");
                    break;
                case "File Open":
                    cardView.show(cardPanel, "Open");
                    break;
                case "Edit Entry":
                    cardView.show(cardPanel, "Edit");
                    break;
                case "Exit":
                    cardView.show(cardPanel, "Exit");
                    break;
                default:
                    System.out.println("Opppsss you pressed something else");
                    break;
            }
        }
    
        private void initComponents(JFrame frame) {
            //Create Menu bar and add to Frame
            menu = new JMenuBar();
            frame.setJMenuBar(menu);
    
            fileMenu = new JMenu("File");
            editMenu = new JMenu("Edit");
            exitMenu = new JMenu("Exit");
    
            menu.add(fileMenu);
            menu.add(editMenu);
            menu.add(exitMenu);
    
            newItem = new JMenuItem("New File");
            openItem = new JMenuItem("File Open");
            editItem = new JMenuItem("Edit Entry");
            exitItem = new JMenuItem("Exit");
    
            fileMenu.add(newItem);
            fileMenu.add(openItem);
            editMenu.add(editItem);
            exitMenu.add(exitItem);
    
            //Declare object cardView and cardPanel and set layout of cardPanel to CardLayout
            cardView = new CardLayout();
            cardPanel = new JPanel(cardView);
    
    
            //Create sub-panels that would correspond to each function in the menu item ex. newItem, openItem etc...
            newPanel = new JPanel();
            openPanel = new JPanel();
            editPanel = new JPanel();
            exitPanel = new JPanel();
    
    
            //add the sub-panels to the main cardpanel 
            cardPanel.add("New", newPanel);
            cardPanel.add("Open", openPanel);
            cardPanel.add("Edit", editPanel);
            cardPanel.add("Exit", exitPanel);
    
            newItem.addActionListener(this);
            openItem.addActionListener(this);
            editItem.addActionListener(this);
            exitItem.addActionListener(this);
    
           frame.getContentPane().add(cardPanel, BorderLayout.CENTER);
        }
    
        public static void main(String... args) {
    
            //create frame and components on EDT
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    CardLayoutWithMenuBar cardLayoutWithMenuBar = new CardLayoutWithMenuBar();
                }
            });
        }
    }
    

    【讨论】:

    • 感谢大卫的建议,我会牢记这一点。此外,我没有像您那样分离初始化组件,因为这是更大程序的一部分。但是我不确定如何实现,所以我只是在简单的上尝试了它。无论如何,你能告诉我为什么我需要在 main 处写下 SwingUtilities.invokeLater... 行吗?这是常见的做法还是为了让程序更安全地执行?
    • @dimas 是的,为了可读性,很抱歉:)。查看这些链接以进一步为您解释:Initial threadsEDT (Event-Dispatch-Thread)
    • 不用担心,大卫,我只是在问,因为我正在自学 Java,除了在论坛上我没有人可以问,所以我所有的编码风格都是我对它如何工作或逻辑流。我不知道任何行业风格,所以再次感谢您提供的提示和链接。
    • @dimas +1 我们都必须从乐于提供帮助的地方学习 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-22
    • 2012-02-12
    相关资源
    最近更新 更多