Auto Hide JMenuBar

When I run the following code, the menu bar shows when the cursor moves to the top of the window. The problem is that when I move the cursor up to open the menu, but don’t select anything, and then move the cursor from the menu bar area, it becomes invisible, but the menu items remain on the screen.

What I'm trying to achieve is the "auto-hide" menu bar, which becomes visible when the mouse enters a specific area in the JFrame.

public class Test extends JFrame { public Test() { setLayout(new BorderLayout()); setSize(300, 300); JMenuBar mb = new JMenuBar(); setJMenuBar(mb); mb.setVisible(false); JMenu menu = new JMenu("File"); mb.add(menu); menu.add(new JMenuItem("Item-1")); menu.add(new JMenuItem("Item-2")); addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { getJMenuBar().setVisible(e.getY() < 50); } }); } public static void main(String args[]) { new Test().setVisible(true); } } 

I think I found a workaround: if the menu bar is visible and the JFrame receives the mousemove event, then send the ESC key to close any open menu.

  addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { if (getJMenuBar().isVisible()) { try { Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_ESCAPE); } catch (AWTException ex) { } } getJMenuBar().setVisible(e.getY() < 50); } }); 

This workaround depends on the appearance (ESC key value). In any case, for me this is normal.

+4
source share
3 answers

Perhaps you can make it work by checking if any menu is selected from JMenuBar:

 public void mouseMoved(MouseEvent e) { JMenuBar lMenu = getJMenuBar(); boolean hasSelectedMenu = false; for (int i=0 ; i< lMenu.getMenuCount() ; ++i) { if (lMenu.getMenu(i).isSelected()) { hasSelectedMenu = true; break; } } if(!hasSelectedMenu) lMenu.setVisible(e.getY() < 50); } 

In this case, it will disappear as soon as you click elsewhere in the JFrame.

However, this is not entirely true, since it would only be updated on mouseMoved. I would recommend you do the same check on mouseClicked to make sure it disappears when clicked without moving.

+2
source

Also works:

 frame.addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { if (menuBar.isSelected()) { try { Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_ESCAPE); SingleSelectionModel sm = menuBar.getSelectionModel(); sm.clearSelection(); } catch (AWTException ex) { } } } }); 
+2
source

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(); } } }; //Delay timer half a second to ensure real mouseOUT Timer timer = new Timer(1000, task); timer.setInitialDelay(500); timer.setRepeats(false); timer.start(); } 

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.

+1
source

Source: https://habr.com/ru/post/1310955/


All Articles