views:

36

answers:

1

I want to be notified when my JPopupMenu is hidden — whether because an item was selected, the menu was dismissed, or setVisible(false) was called on it. Here is my test code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class A extends ComponentAdapter implements Runnable, ActionListener {
    private JButton b;

    public static void main(String[] args) {
        EventQueue.invokeLater(new A());
    }

    public void run() {
        JFrame f = new JFrame("Test");
        b = new JButton("Click me");
        b.addActionListener(this);
        f.add(b);
        f.pack();
        f.setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        JPopupMenu pm = new JPopupMenu();
        pm.addComponentListener(this);
        pm.add("Popup...");
        pm.add("...menu!");
        pm.show(b, 10, 10);
    }

    public void componentShown(ComponentEvent e) { System.out.println("componentShown"); }
    public void componentHidden(ComponentEvent e) { System.out.println("componentHidden"); }
}

Regardless of how I interact with the menu, neither of the two ComponentListener methods are being called. Why is that? Is there different/better/correct way of finding out when my JPopupMenu is hidden?

Thanks,

Cameron

+3  A: 
pm.addPopupMenuListener(new PopupMenuListener() {

    @Override
    public void popupMenuCanceled(PopupMenuEvent e) {
        System.out.println("cancelled");
    }

    @Override
    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
        System.out.println("vanishing");
    }

    @Override
    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
        System.out.println("appearing");
    }
});

Edit: Whoops, looks like somebody chose to answer in the comments. My bad.

Edit 2: With regards to why ComponentListener isn't sending you events on the menu disappearing, this might explain:

The component-hidden and component-shown events occur only as the result of calls to a Component 's setVisible method. For example, a window might be miniaturized into an icon (iconified) without a component-hidden event being fired.

Source: ComponentListener tutorial (non-canonical perhaps, but from the horse's mouth.)

Consider that in conjunction with JPopupMenu's implementation of setVisible:

    public void setVisible(boolean b) {
        // Not supported for MenuComponents
    }

And you might know how it so happens, but not why it happens (what is the justification and where is that properly documented?)

Mark Peters
I would've accepted one of their comments had they been answers. :)I'll leave the question open to see if anyone can tell me why ComponentListeners aren't called for JPopupMenus.
heycam
+1 Although you _could_ improve the formatting. :-)
trashgod
Sorry, couldn't resist!
trashgod
Thanks for the pointer to tutorial. I just checked the JDK sources, and JPopUpMenu does indeed have an implemented setVisible(boolean) method. (And I use it with setVisible(false) to dismiss my menus, too.) From the code I can see that at least the "visible" property change event will be dispatched. Also, show(Component,int,int) calls setVisible(true) at the end. Given this, I can't think of any justification for componentHidden not to be called.
heycam
Digging further, Component.setVisible(boolean) will dispatch the component show/hide events. JPopupMenu.setVisible(boolean), which overrides it, doesn't call super.setVisible() or explicitly dispatch the events.
heycam
Whoops, sorry about that I was saying one thing but looking at another. My edit applied to PopupMenu, but the principle is the same for JPopupMenu. Yes, what I was trying to get at is that code doesn't filter the call up to Component.setVisible.
Mark Peters