I would like to programmatically expand a particular JMenuItem in a JPopup. For example in the code below
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
public class AutoExpandSubMenusDemo extends JFrame {
    private final JPopupMenu popup = new JPopupMenu("Popup");
    public AutoExpandSubMenusDemo() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        JMenu menuB = new JMenu("B");
        menuB.add(new JMenuItem("X"));
        JMenuItem menuY = menuB.add(new JMenuItem("Y"));
        menuB.add(new JMenuItem("Z"));
        popup.add(new JMenuItem("A"));
        popup.add(menuB);
        popup.add(new JMenuItem("C"));
        final JButton button = new JButton("Show Popup Menu");
        button.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                popup.show(button, 0, button.getHeight());
                // Show menuY
            }
        });
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(button);
        getContentPane().add(buttonPanel);
    }
    public static void main(String[] args) {
        AutoExpandSubMenusDemo f = new AutoExpandSubMenusDemo();
        f.setSize(500, 300);
        f.setVisible(true);
    }
}
I would like to expand the popup menu so that the items B(menuB)/Y(menuY) are expanded and selected when the button is pressed.
Sorry if this is something that's easy to do but I've searched around and can't figure it out.
I did find the
MenuSelectionManager.defaultManager().setSelectedPath(...)
however this didn't work when I tried it and the javadoc specifies that it is called from the LaF and should not be called by clients.
Any help is much appreciated.
While I don't recommend doing this, since the documentation itself advises against it, here's how you could do it:
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
public class AutoExpandSubMenusDemo extends JFrame {
    private final JPopupMenu popup = new JPopupMenu("Popup");
    public AutoExpandSubMenusDemo() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        final JMenu menuB = new JMenu("B");
        menuB.add(new JMenuItem("X"));
        final JMenuItem menuY = menuB.add(new JMenuItem("Y"));
        menuB.add(new JMenuItem("Z"));
        popup.add(new JMenuItem("A"));
        popup.add(menuB);
        popup.add(new JMenuItem("C"));
        final JButton button = new JButton("Show Popup Menu");
        button.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                popup.show(button, 0, button.getHeight());
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        menuB.setPopupMenuVisible(true);
                        MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{popup, menuB, menuY});
                    }
                });
            }
        });
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(button);
        getContentPane().add(buttonPanel);
    }
    public static void main(String[] args) {
        AutoExpandSubMenusDemo f = new AutoExpandSubMenusDemo();
        f.setSize(500, 300);
        f.setVisible(true);
    }
}
Most of this code is yours. I only added:
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        menuB.setPopupMenuVisible(true);
        MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{popup, menuB, menuY});
    }
});
which seems to work.
You could avoid abusing MenuSelectionManager via 'MenuItem.setArmed(boolean)'.
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        menuB.setPopupMenuVisible(true);
        menuB.setArmed(true);
        menuY.setArmed(true);
    }
});
The popup staying visible after selecting another menu item or dismissing the JPopupMenu still needs to be addressed though.
Another way is to fake a mouse event... :D
SwingUtilities.invokeLater(new Runnable() {
    public void run() {                        
        MouseEvent event = new MouseEvent(
                menuB, MouseEvent.MOUSE_ENTERED, 0, 0, 0, 0, 0, false);
        menuB.dispatchEvent(event);
        menuY.setArmed(true);
    }
});
This way it is as if the user actually used the mouse.
Another example:
MenuSelectionManager.defaultManager().setSelectedPath(
    new MenuElement[] {popup, menuB, menuB.getPopupMenu()});

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AutoExpandSubMenusDemo2 extends JFrame {
  private final JPopupMenu popup = new JPopupMenu("Popup");
  public AutoExpandSubMenusDemo2() {
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    final JMenu menuB = new JMenu("B");
    menuB.add(new JMenuItem("X"));
    final JMenuItem menuY = menuB.add(new JMenuItem("Y"));
    menuB.add(new JMenuItem("Z"));
    popup.add(new JMenuItem("A"));
    popup.add(menuB);
    popup.add(new JMenuItem("C"));
    JPanel buttonPanel = new JPanel();
    buttonPanel.add(new JButton(new AbstractAction("Show menuB Popup") {
      @Override public void actionPerformed(ActionEvent e) {
        JButton button = (JButton) e.getSource();
        popup.show(button, 0, button.getHeight());
        //[Bug ID: JDK-6949414 JMenu.buildMenuElementArray() endless loop]
        //( http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6949414 )
        //menuB.doClick();
        MenuSelectionManager.defaultManager().setSelectedPath(
          new MenuElement[] {popup, menuB, menuB.getPopupMenu()});
      }
    }));
    buttonPanel.add(new JButton(new AbstractAction("Select menuY") {
      @Override public void actionPerformed(ActionEvent e) {
        JButton button = (JButton) e.getSource();
        popup.show(button, 0, button.getHeight());
        MenuSelectionManager.defaultManager().setSelectedPath(
          new MenuElement[] {popup, menuB, menuB.getPopupMenu(), menuY});
      }
    }));
    getContentPane().add(buttonPanel);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new AutoExpandSubMenusDemo2();
    f.setSize(500, 300);
    f.setVisible(true);
  }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With