JPopupMenu won't close if I click outside of it

//_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);

    }
}

There are know bugs when using JPopupMen: JTrayIcon: support Swing JPopupMenus for tray icons. Near the end is a link to a possible solution. I haven't tried it so I don't know if it will fix your problem or not.


In the end I "solved" this by hacking around the issue. As Camickr points out, JPopupMenu is pretty buggy. However it is the only Swing popup menu implementation that allows you to have an icon next to each menu element.

My solution was to implement a listener on the jpopupmenu that, if the user put the mouse over the menu, after 3 seconds it would be set to .isVisible(false) if the user did not put the mouse back over the menu within that time.

In order to achieve this, I had to use a separate Thread which constantly checked if the popupmenu was active. If so, check if the mouse was over it, using an event listener, and set visibility to false if the user didn't enter it again within 3 seconds.

This is not a perfect solution as the user still has to wait 3 seconds for the menu to disappear (it should be instant if he/she clicks away) and it will disappear even if it is in focus (it should not unless the user clicks away). However, it felt 'good enough' to be accepted.

Hope that helps.

Tags:

Java

Swing