You can also add a transparent panel area to your window and attach a separate MouseListener to that area so you can make an invisible menu! but this idea is not included in my example.
Below is a fully working AutoHide Hierarchical MenuBar taken from my live application:
The way I decided to close the menu was to run the boolean variable "isMouseOut" at the top of the constructor for tracking, and then highlight MouseListener in a more convenient way for OO to track multiple MouseIn Events —MouseOut as the user interacts with the menu. Which calls a separate menuClear method that acts on the state of the logical "isMouseOut". The class implements MouseListener. Here's how to do it.
Create an ArrayList by first adding all the menu items to this array. For instance:
Font menuFont = new Font("Arial", Font.PLAIN, 12); JMenuBar menuBar = new JMenuBar(); getContentPane().add(menuBar, BorderLayout.NORTH); // Array of MenuItems ArrayList<JMenuItem> aMenuItms = new ArrayList<JMenuItem>(); JMenuItem mntmRefresh = new JMenuItem("Refresh"); JMenuItem mntmNew = new JMenuItem("New"); JMenuItem mntmNormal = new JMenuItem("Normal"); JMenuItem mntmMax = new JMenuItem("Max"); JMenuItem mntmStatus = new JMenuItem("Status"); JMenuItem mntmFeedback = new JMenuItem("Send Feedback"); JMenuItem mntmEtsyTWebsite = new JMenuItem("EtsyT website"); JMenuItem mntmAbout = new JMenuItem("About"); aMenuItms.add(mntmRefresh); aMenuItms.add(mntmNew); aMenuItms.add(mntmNormal); aMenuItms.add(mntmMax); aMenuItms.add(mntmStatus); aMenuItms.add(mntmFeedback); aMenuItms.add(mntmEtsyTWebsite); aMenuItms.add(mntmAbout);
then go through the list array at this point by adding a MouseListener using a for () loop:
for (Component c : aMenuItms) { if (c instanceof JMenuItem) { c.addMouseListener(ml); } }
Now set the JMenu parents for the MenuBar:
// Now set JMenu parents on MenuBar final JMenu mnFile = new JMenu("File"); menuBar.add(mnFile).setFont(menuFont); final JMenu mnView = new JMenu("View"); menuBar.add(mnView).setFont(menuFont); final JMenu mnHelp = new JMenu("Help"); menuBar.add(mnHelp).setFont(menuFont);
Then add the Children Items drop-down menu to JMenu's parents:
// Now set menuItems as children of JMenu parents mnFile.add(mntmRefresh).setFont(menuFont); mnFile.add(mntmNew).setFont(menuFont); mnView.add(mntmNormal).setFont(menuFont); mnView.add(mntmMax).setFont(menuFont); mnHelp.add(mntmStatus).setFont(menuFont); mnHelp.add(mntmFeedback).setFont(menuFont); mnHelp.add(mntmEtsyTWebsite).setFont(menuFont); mnHelp.add(mntmAbout).setFont(menuFont);
Add mouseListeners to JMenu parents as a separate step:
for (Component c : menuBar.getComponents()) { if (c instanceof JMenu) { c.addMouseListener(ml); } }
Now that the elements of the childEtem element have their own listeners, which are separate for the parent elements of JMenu and the MenuBar itself, it is important to identify the type of the object in the MouseListener () instance so that you automatically open the mouseover menu (in this example, 3x of the JMenu parent), BUT ALSO avoids the errors of child exceptions and allows you to clear the mouseout identification of the menu structure without trying to control where the mouse position is. MouseListener looks like this:
MouseListener ml = new MouseListener() { public void mouseClicked(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseExited(MouseEvent e) { isMouseOut = true; timerMenuClear(); } public void mouseEntered(MouseEvent e) { isMouseOut = false; Object eSource = e.getSource(); if(eSource == mnHelp || eSource == mnView || eSource == mnFile){ ((JMenu) eSource).doClick(); } } };
The above only simulates a mouse click on JMenu's parents (3x in this example), since they are triggers for the drop-down menus of the child menu. The timerMenuClear () method calls MenuSelectionManager in order to empty any selected waypoint in real time at the time of the real mouse:
public void timerMenuClear(){ ActionListener task = new ActionListener() { public void actionPerformed(ActionEvent e) { if(isMouseOut == true){ System.out.println("Timer"); MenuSelectionManager.defaultManager().clearSelectedPath(); } } };
It took me a bit of testing, keeping track of what values I could get in the JVM during its development, but it works! even with nested menus :) I hope many find this complete example very useful.