JPopupMenu如果在外部点击不会关闭

8
我创建了一个Java Swing应用程序,它没有可见的主窗口,但可以通过右键单击其托盘图标来控制。
我使用了一个JPopupMenu来实现这一点,但是当我在弹出菜单之外点击(例如另一个应用程序的窗口或桌面)时,JPopupMenu不会消失,这不是预期的行为。
最初我使用的是一个弹出菜单,它的工作符合预期,但这样做不允许我在菜单中放置图标。
如何使其在我点击其他地方时按预期关闭?
4个回答

7
//_Popup is your JPopupMenu, call this method before setting your popup to visible
public void armPopup()
{
    if(_Popup != null)
    {
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener()
        {
            @Override
            public void eventDispatched(AWTEvent event) {

                if(event instanceof MouseEvent)
                {
                    MouseEvent m = (MouseEvent)event;
                    if(m.getID() == MouseEvent.MOUSE_CLICKED)
                    {
                        _Popup.setVisible(false);
                        Toolkit.getDefaultToolkit().removeAWTEventListener(this);
                    }
                }
                if(event instanceof WindowEvent)
                {
                    WindowEvent we = (WindowEvent)event;
                    if(we.getID() == WindowEvent.WINDOW_DEACTIVATED || we.getID() == WindowEvent.WINDOW_STATE_CHANGED)
                    {
                        _Popup.setVisible(false);
                        Toolkit.getDefaultToolkit().removeAWTEventListener(this);
                    }
                }
            }

        }, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.WINDOW_EVENT_MASK);

    }
}

如果操作系统将它直接放在可见的托盘部分,它可以在Windows 10上正常工作,但是如果操作系统将图标放在“可折叠子托盘”或其他面板中,则会失败。 - Haroldo_OK

2

2
最终,我通过绕过此问题来“解决”了它。正如Camickr所指出的那样,JPopupMenu非常有缺陷。然而,它是唯一一个允许你在每个菜单元素旁边拥有图标的Swing弹出菜单实现。
我的解决方案是在jpopupmenu上实现一个监听器,如果用户将鼠标悬停在菜单上,3秒后如果用户没有在该时间内将鼠标放回菜单,则会将其设置为.isVisible(false)。
为了实现这一点,我必须使用一个单独的线程来不断检查弹出菜单是否处于活动状态。如果是,使用事件监听器检查鼠标是否悬停在上面,并在用户在3秒内未再次进入时将其隐藏。
这并不是一个完美的解决方案,因为用户仍然需要等待3秒钟才能使菜单消失(如果他/她点击其他地方应该是立即消失的),并且即使它处于焦点状态也会消失(除非用户点击其他地方)。但是,它感觉“足够好”可以被接受。
希望对你有所帮助。

0

最近我一直在处理这个“老”问题。 这是我的解决方案,它很好地达到了我的期望。

我向托盘图标类添加了一个未装饰的透明窗口,并将FocusListener附加到它上面。 当触发弹出窗口要显示时,鼠标事件也会触发透明窗口的显示(由于其透明度无法看到)。 窗口获得焦点事件。 当鼠标在弹出窗口外的屏幕上某处单击时,触发透明窗口的focusLost事件。 现在可以使用此事件将弹出窗口设置为不可见。

public MyTrayIconApp() {
    if (!SystemTray.isSupported()) {
        System.out.println("SystemTray is not supported");
        System.exit(0);
    }

    // work around to close popup if mouse is clicked outside of popup
    transparentWindow = new JFrame();
    transparentWindow.setType(JFrame.Type.UTILITY);  // avoid task bar icon
    transparentWindow.setUndecorated(true);
    transparentWindow.setOpacity(0.0f);
    transparentWindow.addFocusListener(new FocusListener(){
        @Override
        public void focusGained(FocusEvent e) {}

        @Override
        public void focusLost(FocusEvent e) {
            if (popup.isVisible())
                popup.setVisible(false);
                transparentWindow.dispose();
        }           
    });        
    
    popup = new JPopupMenu();
    icon = new ImageIcon(IndexWatcherTrayIcon.class.getResource("/16x16/myIcon.png"));
    trayIcon = new TrayIcon(icon);
    tray = SystemTray.getSystemTray();

    // Create pop-up menu components
    JMenuItem startstopItem = new JMenuItem("Stop");
    JMenuItem updateItem = new JMenuItem("Update Indexes");
    JMenuItem exitItem = new JMenuItem("Exit");        
  
    // Add components to pop-up menu       
    popup.add(startstopItem);
    popup.add(updateItem);
    popup.addSeparator();
    popup.add(exitItem);
    
    // Add mouse listener to tray icon
    trayIcon.addMouseListener(new MouseAdapter() {                   
        @Override
        public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    transparentWindow.setVisible(true);
                    popup.setLocation(e.getX(), e.getY());
                    popup.setInvoker(popup);
                    popup.setVisible(true);                                  
                }         
            }
        });
    
    // Add tray icon to system tray              
    try {
        tray.add(trayIcon);
    } catch (AWTException e) {
        System.out.println("TrayIcon could not be added.");
    }         
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接