Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically expand sub JMenuItems

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.

like image 872
Jamesy82 Avatar asked Aug 12 '14 09:08

Jamesy82


2 Answers

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.

like image 100
predi Avatar answered Sep 27 '22 19:09

predi


Another example:

MenuSelectionManager.defaultManager().setSelectedPath(
    new MenuElement[] {popup, menuB, menuB.getPopupMenu()});

enter image description here

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);
  }
}
like image 34
aterai Avatar answered Sep 27 '22 21:09

aterai