2010-05-26 76 views
4

当我运行下面的代码时,菜单栏显示光标何时移动到窗口的上部。问题是,当我向上移动光标以打开菜单但不选择任何内容时,然后将光标移出菜单栏区域时,它将变为不可见,但菜单的元素保留在屏幕上。自动隐藏JMenuBar

我试图实现的是一个“自动隐藏”菜单栏,当鼠标进入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); 
    } 
} 

我想我找到了一个解决方法:如果在菜单栏是可见的,JFrame中接收到鼠标移动事件,然后发送ESC键关闭所有打开的菜单。

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); 
      } 
     }); 

此替代方法取决于外观(ESC键的含义)。 无论如何,对我来说没关系。

+0

我想过尝试在getJMenuBar()。isSelected()方法中添加一个条件,但不幸的是,即使将选择放入另一个组件,选择模型也不会更新回false,之后消失。 – Gnoupi 2010-05-26 10:17:00

回答

2

你或许可以使其通过检查的工作是选择任何菜单,从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); 
} 

在这种情况下,它会为你点击别的地方在JFrame中立即消失。

但是,不完全一样,因为它只会更新mouseMoved。我建议你对mouseClicked做同样的检查,确保它在点击时不会移动而消失。

2

也可以工作:

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) { 
       } 

      } 
     } 
    }); 
1

你也可以添加一个透明的面板区域到窗口中,附上一份单独的MouseListener该区域面板,这样就可以使一个无形的菜单出现!但这个想法并未包含在我的例子中。

下面是从我的生活应用程序采取了一个有效的自动隐藏分层菜单栏:

我解决了鼠标在菜单关闭的方法是在构造顶部运行布尔变量“isMouseOut”保持跟踪,然后以更友好的OO方式分配MouseListener,以便跟踪用户与菜单交互时的多个MouseIn-MouseOut事件。它调用一个单独的menuClear方法来处理布尔型“isMouseOut”的状态。该类实现MouseListener。这是如何完成的。

创建一个ArrayList,首先将所有菜单项添加到该数组中。像这样:

for (Component c : aMenuItms) { 
     if (c instanceof JMenuItem) { 
      c.addMouseListener(ml); 
     } 
    } 

现在设置JMenu的父母为菜单栏:

// 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); 

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); 

那么在这个阶段使用for()循环添加的MouseListener在ArrayList的迭代然后将下拉菜单项子项添加到JMenu父项:

// 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); 

添加mouseListeners到JMenu父母作为单独的步骤:

for (Component c : menuBar.getComponents()) { 
     if (c instanceof JMenu) { 
      c.addMouseListener(ml); 
     } 
    } 

现在孩子菜单项元素都有自己的听众,是独立于母公司JMenu的元素和菜单栏本身 - 识别是很重要的MouseListener()实例中的对象类型,以便您可以在鼠标悬停时获得菜单自动打开(在本例中为3x JMenu父项),但也避免子例外错误,并允许清理识别菜单结构的mouseOUT,而不尝试监视鼠标位置是。该的MouseListener如下:

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(); 
      } 
     } 
    }; 

以上只是模拟鼠标点击进入JMenu的父母(3次在这个例子中),因为它们是为孩子菜单的下拉列表中的触发器。该timerMenuClear()方法调用的对象MenuSelectionManager清空任何selectedpath点是活在真实的鼠标移开时:

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(); 
} 

我花了一个小测试,监测什么样的价值观,我可以在其发展过程中的JVM内访问 - 但它适用于一种享受!即使嵌套菜单:)我希望很多人发现这个完整的例子非常有用。