Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't componentHidden called for my JPopupMenu?

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

like image 593
heycam Avatar asked Jun 14 '10 03:06

heycam


1 Answers

JPopupMenu has a special listener for visibility change events:

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

Note, however, as method names hint, they are called before visibility changes, so if you're calling isVisible() somewhere in the event handlers, you should be aware of that, for example:

@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    updateMenu();
}

private void updateMenu() {
    if (!menu.isVisible()) { // this won't work!
        // perform some updates
    }
}

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?)

like image 111
Mark Peters Avatar answered Oct 14 '22 07:10

Mark Peters