Search code examples
javaswingjmenu

Can't Add JMenuItem to JMenu in JPopupMenu


I've got a new UI I'm working on implementing in Java and I'm having trouble implementing a JPopupMenu containing a JMenu (as well as several JMenuItems), which itself contains several JMenuItems. The JPopupMenu appears where I click the RMB, and it looks good, but the "Connect" JMenu doesn't seem to have any children when I mouse-over, despite my best efforts to .add() them.
enter image description here

Having looked at several examples online, I haven't seen any that specifically implement a listener for mouseEntered() to roll out the sub-items. I'm of a mind that I'm messing something up in my menu initialization method.

I've attached the pertinent code for your perusal.

//Elsewhere...
private JPopupMenu _clickMenu;
//End Elsehwere...

private void initializeMenu()
{
    _clickMenu = new JPopupMenu();
    _clickMenu.setVisible(false);

    _clickMenu.add(generateConnectionMenu());

    JMenuItem menuItem;
    menuItem = new JMenuItem("Configure");
    addMenuItemListeners(menuItem);
    _clickMenu.add(menuItem);

    menuItem = new JMenuItem("Status");
    addMenuItemListeners(menuItem);
    _clickMenu.add(menuItem);
}

private JMenu generateConnectionMenu()
{
    JMenu menu = new JMenu("Connect");

    List<Port> portList = _database.getAllPortsInCard(_cardId);

    for(int i = 0; i < portList.size(); i++)
    {
        menu.add(new JMenuItem(portList.get(i).getName()));
    }

    return menu;
}

The code is certainly not the prettiest, but go easy on me as it's been altered too many times today as time permitted while I tried to figure out why this wasn't working. I'm thinking it may be a question of scope, but I've tried a few different code configurations to no avail. Feel free to ask any followup questions or smack me for an obvious oversight (it's happened before...). Thanks all!

Edit: Chalk this one up to a lack of experience with Java and Swing... I was manually positioning and making the JPopupMenu visible instead of using the JComponent.setComponentPopupMenu(menu) method. After doing this for the card module in the above image (itself a JButton), the submenu displays correctly. A different, functional version of the initialization code is included below.

    private void initializeMenu()
{
    _cardMenu = new JPopupMenu();

    JMenu menu = new JMenu("Connect");

    JMenuItem menuItem;
    menuItem = new JMenuItem("1");
    menu.add(menuItem);

    menuItem = new JMenuItem("2");
    menu.add(menuItem);

    _cardMenu.add(menu);
    _cardMenu.add(new JMenuItem("Configure"));
    _cardMenu.add(new JMenuItem("Status"));

    _mainButton.setComponentPopupMenu(_cardMenu); //Important, apparently!
}

So, lesson learned. Thanks for the help guys!


Solution

  • This is common Bug or Swing property that in one moment can be visible only one Lightweight popup window, same issue is e.g. with popup from JComboBox added into JPopupMenu,

    • change Lightweight property to the Heavyweight

    better would be

    • use un_decorated JDialog or JOptionPane with JComponents

    EDIT @trashgod

    • everything works as I excepted, all JMenus, JMenuItems are visible and repeatly fired correct evets

    code

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.event.*;
    
    public class ContextMenu implements ActionListener, MenuListener, MenuKeyListener {
    
        private JTextArea textArea = new JTextArea();
    
        public ContextMenu() {
            final JPopupMenu contextMenu = new JPopupMenu("Edit");
            JMenu menu = new JMenu("Sub Menu");
            menu.add(makeMenuItem("Sub Menu Save"));
            menu.add(makeMenuItem("Sub Menu Save As"));
            menu.add(makeMenuItem("Sub Menu Close"));
            menu.addMenuListener(this);
            JMenu menu1 = new JMenu("Sub Menu");
            menu1.add(makeMenuItem("Deepest Sub Menu Save"));
            menu1.add(makeMenuItem("Deepest Sub Menu Save As"));
            menu1.add(makeMenuItem("Deepest Sub Menu Close"));
            menu.add(menu1);
            menu1.addMenuListener(this);
            contextMenu.add(menu);
            contextMenu.add(makeMenuItem("Plain Save"));
            contextMenu.add(makeMenuItem("Plain Save As"));
            contextMenu.add(makeMenuItem("Plain Close"));
            contextMenu.addMenuKeyListener(this);
            JFrame frame = new JFrame();
            JPanel panel = new JPanel();
            panel.setLayout(new BorderLayout());
            frame.add(panel);
            panel.setComponentPopupMenu(contextMenu);
            textArea.setInheritsPopupMenu(true);
            panel.add(BorderLayout.CENTER, textArea);
            JTextField textField = new JTextField();
            textField.setInheritsPopupMenu(true);
            panel.add(BorderLayout.SOUTH, textField);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 200);
            frame.setVisible(true);
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            textArea.append(e.getActionCommand() + "\n");
        }
    
        private JMenuItem makeMenuItem(String label) {
            JMenuItem item = new JMenuItem(label);
            item.addActionListener(this);
            return item;
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    ContextMenu contextMenu = new ContextMenu();
                }
            });
        }
    
        public void menuSelected(MenuEvent e) {
            textArea.append("menuSelected" + "\n");
        }
    
        public void menuDeselected(MenuEvent e) {
            textArea.append("menuDeselected" + "\n");
        }
    
        public void menuCanceled(MenuEvent e) {
            textArea.append("menuCanceled" + "\n");
        }
    
        public void menuKeyTyped(MenuKeyEvent e) {
            textArea.append("menuKeyTyped" + "\n");
        }
    
        public void menuKeyPressed(MenuKeyEvent e) {
            textArea.append("menuKeyPressed" + "\n");
        }
    
        public void menuKeyReleased(MenuKeyEvent e) {
            textArea.append("menuKeyReleased" + "\n");
        }
    }