【发布时间】:2016-11-20 23:10:16
【问题描述】:
我知道如何使用 JMenu 创建 Java Swing 子菜单。当我们将鼠标悬停在 JMenu 对象上时,它会显示一个显示子菜单项的 JPopupMenu,如下所示:
使用 JMenu 的子菜单
我的问题是,在我的应用程序中,确定哪些菜单元素将具有子菜单的成本很高。我不想提前确定一个特定的菜单元素应该是一个 JMenu 还是一个 JMenuItem。我想让每个元素都成为 JMenuItem 并仅在用户请求时为其显示子菜单,例如,将鼠标悬停在菜单项上。像这样:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Menu2 extends JFrame
{
public Menu2()
{
super("Menu2");
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu mItems = new JMenu("Items");
menuBar.add(mItems);
mItems.add(new JMI("A"));
mItems.add(new JMI("B"));
mItems.add(new JMI("C"));
JLabel stuff = new JLabel("Other stuff");
stuff.setPreferredSize(new Dimension(200,200));
getContentPane().add(stuff);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private class JMI extends JMenuItem
implements MouseListener
{
public JPopupMenu childrenPopup = null;
public JMI(String label)
{
super(label);
addMouseListener(this);
}
// MouseListener
public void mouseClicked(MouseEvent ev) {}
public void mouseEntered(MouseEvent ev)
{
// Show a submenu for item "B" only.
// In real life we'd want a Timer to delay showing the submenu
// until we are sure the user is hovering the mouse.
// For simplicity I've omitted it.
if (getText().equals("B")) {
if (childrenPopup == null) {
childrenPopup = new JPopupMenu();
// Expensive processing to determine submenu elements...
childrenPopup.add("D");
childrenPopup.add("E");
}
// Display the submenu
childrenPopup.show(this,getWidth(),0);
}
}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
}
public static void main(String[] args)
throws Exception
{
new Menu2().setVisible(true);
}
}
唯一的问题是,当我手动创建的 JPopupMenu 显示时,菜单的其余部分会关闭。结果显示看起来不像之前的那样,而是像这样:
手动显示子菜单
请注意,我没有单击“B”菜单项,只是将鼠标移入其中。由于单击鼠标,菜单未关闭。
我怎样才能做 JMenu 所做的——在不关闭菜单其余部分的情况下显示 JPopupMenu?
【问题讨论】:
-
也许你可以尝试用 JMenu 替换 JMenuItem,一旦你确定它确实有子菜单。
-
我认为像这样的新成语会让用户感到困惑,你最好让你的菜单条目始终是一个 JMenuItem,它会打开一个模式对话框(可能是一个 JOptionPane)显示动态确定的选择。
-
感谢 camickr 和 VGR 对解决方法的建议。即使我必须使用解决方法,我也很想知道为什么显示弹出窗口会导致菜单关闭。显然它可以在不关闭菜单的情况下完成,因为 JMenu 会这样做。
-
研究 JDK 代码,我至少弄清楚是怎么回事。如果在 JPopupMenu.show() 中指定的“调用者”不是 JMenu 的实例,则 JPopupMenu 确定它是“独立”弹出窗口并调用 MenuSelectionManager.setSelectedPath() 以使其自身成为唯一的路径元素。 MenuSelectionManager 然后关闭所有以前的路径元素。现在要找到一个好的解决方案......