我有JPopupMenu
,其中包含内部JMenu
和包含addSeparator()
的分隔符。由于一些奇怪的处理,我在MouseListener
添加了JPopupMenu
,这使mouseExited
事件无法看到它。这很好用,除了当鼠标试图越过分隔符时,它会触发事件(即使JPopupMenu
是超级组件)。
如果我删除addSeparator()
行,则按预期工作。
有什么方法可以解决这个问题吗?或者我没有正确设置听众?
代码如下:
JPopupMenu popupMenu = new JPopupMenu();
JMenu innerMenu = new JMenu("Inner");
// ... add JMenuItems
popupMenu.add(innerMenu);
popupMenu.addSeparator();
popupMenu.add(new JMenuItem("Exit"));
popupMenu.addMouseListener(new MouseAdapter() {
@Override
public void mouseExited(MouseEvent e) {
popupMenu.setVisible(false);
}
});
完全可编辑示例
只需评论并取消注释 popupMenu.addSeparator()
行即可注意不同的行为
public class Test {
public static void main(String[] args) throws Exception {
if(!SystemTray.isSupported()) {
throw new UnsupportedOperationException("SystemTray is not supported.");
}
final TrayIcon trayIcon = new TrayIcon(ImageIO.read(new File("resources/icon.gif")));
final JPopupMenu popupMenu = new JPopupMenu();
JMenu intervalMenu = new JMenu("Interval");
ButtonGroup itemGroup = new ButtonGroup();
JRadioButtonMenuItem oneSecondMenuItem = new JRadioButtonMenuItem("1 sec");
itemGroup.add(oneSecondMenuItem);
JRadioButtonMenuItem twoSecondMenuItem = new JRadioButtonMenuItem("2 sec");
itemGroup.add(twoSecondMenuItem);
intervalMenu.add(oneSecondMenuItem);
intervalMenu.add(twoSecondMenuItem);
popupMenu.add(intervalMenu);
popupMenu.addSeparator();
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
SystemTray.getSystemTray().remove(trayIcon);
System.exit(0);
}
});
popupMenu.add(exitMenuItem);
//Thanks to Artem Ananiev for this implementation idea
//https://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html
trayIcon.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON3) {
popupMenu.setLocation(e.getX() - 40, e.getY() - 40);
popupMenu.setInvoker(popupMenu);
popupMenu.setVisible(true);
}
}
});
popupMenu.addMouseListener(new MouseAdapter() {
@Override
public void mouseExited(MouseEvent e) {
popupMenu.setVisible(false);
}
});
SystemTray.getSystemTray().add(trayIcon);
}
}
答案 0 :(得分:3)
无论如何,以下似乎都有效:
if (! popupMenu.contains( e.getPoint() ) )
popupMenu.setVisible(false);
编辑:
看起来问题是JSeparator默认不监听MouseEvents,因此所有鼠标事件都传递给它的父级。因此,当您离开JMenuItem时,会为弹出菜单生成mouseEntered()事件,然后当您重新输入另一个JMenuItem时,将生成mouseExited()事件。
如果为JSeparator启用MouseEvents,那么它看起来就像JPopupMenu没有得到事件
//popupMenu.addSeparator();
popupMenu.add( new MySeparator() );
...
static class MySeparator extends JSeparator
{
public MySeparator( )
{
super( JSeparator.HORIZONTAL );
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* Returns the name of the L&F class that renders this component.
*
* @return the string "PopupMenuSeparatorUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID()
{
return "PopupMenuSeparatorUI";
}
}