【问题标题】:MouseExited event triggers when crossing an inner separator?跨越内部分隔符时触发 MouseExited 事件?
【发布时间】:2013-10-24 16:00:24
【问题描述】:

我有一个JPopupMenu,其中包含一个内部JMenu 和一个带有addSeparator() 的分隔符。由于一些奇怪的处理,我在JPopupMenu 中添加了一个MouseListener,这使它在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);
    }

}

【问题讨论】:

  • 发布您的 SSCCE 来证明问题。
  • @camickr 完成。让它尽可能简洁,即使它是一个复杂的设置。

标签: java swing mouselistener system-tray jpopupmenu


【解决方案1】:

哇,您正在使用系统托盘图标。这些信息可能很重要。这就是为什么每个问题都应该发布 SSCCE。

无论如何,以下似乎有效:

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

    }
}

【讨论】:

  • 是的,效果很好!感谢您的解决方法。知道一开始发生了什么吗?对我来说似乎真的很奇怪。没有猜到发生了什么。
  • 非常有趣。感谢您的洞察力。很高兴知道。
猜你喜欢
  • 2014-01-31
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多