7

在第一次单击之前, JMenuBar 不会开始将JMenuItem显示为选中状态或显示JMenu弹出窗口。单击JMenuBar中的某个位置后,所有这些项目都会响应鼠标悬停。

我想绕过所需的初始点击,并在鼠标悬停时自动激活它。有没有办法做到这一点?

4

2 回答 2

9

方法是添加一个MouseListeneron theJMenu并监听 events mouseEntered。在事件处理程序中,您只需使用doClick. 例如,

jMenuFile.addMouseListener(new MouseListener(){
    public void mouseEntered(MouseEvent e) {
       jMenuFile.doClick();
    }
  ...
});

一旦以编程方式单击鼠标,它就会自动打开弹出菜单。要激活一个整体JMenuBar,您必须在每个上添加一个侦听器JMenu。为此,最好单独创建一个监听器对象。

我在栏上有两个菜单项,所以我做了:

MouseListener ml = new MouseListener(){
    public void mouseClicked(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {
        ((JMenu)e.getSource()).doClick();
    }
  };
  jMenuFile.addMouseListener(ml);
  jMenuHelp.addMouseListener(ml);

如果栏上有这么多菜单项,则可以对其进行迭代:

for (Component c: jMenuBar1.getComponents()) {
    if (c instanceof JMenu){
        c.addMouseListener(ml);
    }
}
于 2012-08-25T20:47:39.960 回答
2

Roman C 的初始和接受的答案不会 AUTO Close the menu with child MenuItems 作为 JMenuBar 的一部分。

运行 ((JMenu)e.getSource()).doClick(); 在 mouseEntered 上模拟单击到 JMenu 父级之一,但不能简单地添加到 mouseExited 方法,因为 MouseListener 需要附加到子 MenuItems 以及 JMenu 父级。(在对 MenuBar 的正常分配中它不会这样做 - 仅附加到父 JMenu 对象)。

此外,由于试图让 MouseExit 侦听器仅在鼠标离开整个菜单结构(即子菜单下拉菜单)时触发“关闭”方法而出现问题。

以下是从我的实时应用程序中获取的完整工作答案:

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

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

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

然后在此阶段迭代 arrayList,使用 for() 循环添加 MouseListener:

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

现在为 MenuBar 设置 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);

然后将下拉 menuItems 子项添加到 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);
        }
    }

现在子 menuItem 元素都有自己的侦听器,这些侦听器与父 JMenu 元素和 MenuBar 本身是分开的 - 在 MouseListener() 实例化中识别对象类型很重要,这样您就可以在鼠标悬停时自动打开菜单(在这个例子是 3x JMenu 父级)但也避免了子异常错误,并允许在不尝试监视鼠标位置的情况下干净地识别菜单结构的 mouseOUT。鼠标监听器如下:

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 'parents'(本例中为 3x),因为它们是子菜单下拉菜单的触发器。timerMenuClear() 方法调用 MenuSelectionManager 以清空在真正 mouseOUT 时处于活动状态的任何选定路径点:

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 中访问哪些值 - 但它确实是一种享受!即使有嵌套菜单 :) 我希望很多人发现这个完整的例子非常有用。

于 2015-01-02T01:18:10.403 回答