JMenuBar在第一次点击时没有开始显示JMenuItem被选中或显示JMenu弹出窗口。单击JMenuBar中的某个位置后,所有这些项都会响应鼠标悬停。
我想绕过所需的初始点击,并在鼠标悬停时自动激活它。有没有办法做到这一点?
答案 0 :(得分:9)
方法是在MouseListener
上添加JMenu
并监听事件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);
}
}
答案 1 :(得分:1)
Roman C的初始和接受的答案将不会自动关闭菜单,其中子MenuItems作为JMenuBar的一部分。
运行((JMenu)e.getSource())。doClick();在mouseEntered上模拟了单击其中一个JMenu父项,但不能简单地添加到mouseExited方法,因为MouseListener需要附加到子MenuItems以及JMenu父项。 (它在正常分配给MenuBar时没有做 - 只附加到父JMenu对象)。
此外,由于尝试让MouseExit侦听器触发"关闭"而出现问题。方法仅当鼠标离开整个菜单结构时(即子菜单下拉菜单)。
以下是从我的实时应用中获得的完整解决方案:
我解决鼠标输出关闭菜单的方法是运行一个布尔变量" isMouseOut"在构造函数的顶部进行跟踪,然后以更友好的方式分配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);
然后将下拉菜单项目子项添加到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()实例化中识别对象类型非常重要,这样就可以自动打开菜单了。 mouseover(在本例中为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&#39;父母&#39; (在此示例中为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在开发过程中可以访问的值 - 但是它有效!即使有嵌套菜单:)我希望很多人觉得这个完整的例子非常有用。