2

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!

Rich Hoffman
  • 742
  • 1
  • 7
  • 23

2 Answers2

2

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");
    }
}
Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Ah, thank you! This works correctly on Mac OS X. I notice that your factory method `makeMenuItem()` helps avoid the problems common to re-using local variables. Sorry I can't up-vote again. – trashgod Apr 03 '12 at 08:05
  • edited with arest of listeners, works as I expected, WinXP, Java6 – mKorbel Apr 03 '12 at 08:05
2

I don't see an obvious problem in the code shown, although @mKorbel's point may apply. For reference, this ControlPanel adds a subMenu with several items.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045