1

I want to log every time any JPopupMenu is shown (visible).

I tried to catch via AWT Events, but MouseEvent does not provide JPopupMenu due JPopupMenu might still be generating and not yet visible

I wonder if there some trick so I can catch when any JPopupMenu is shown without adding listeners to each JPopupMenu currently used in an App

VextoR
  • 5,087
  • 22
  • 74
  • 109
  • 2
    Individually, probably not. What might be better is to have a factory or builder which can produce a `JPopupMenu` which you have control of, from which you can then monitor yourself – MadProgrammer May 18 '23 at 22:04

2 Answers2

1

It seems like focus is given to the JRootPane whenever a JPopupMenu is shown. You can listen for this event by using a KeyboardFocusManager:

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

public class PopupListener extends JPanel
{
    JPopupMenu menu;

    public PopupListener()
    {
        menu = new JPopupMenu();
        menu.add( new JMenuItem( "Cut" ) );
        menu.add( new JMenuItem( "Copy" ) );
        menu.add( new JMenuItem( "Paste" ) );

        MouseListener ml = new MouseAdapter()
        {
            public void mouseReleased(MouseEvent e)
            {
                if (e.isPopupTrigger())
                {
                    menu.show(e.getComponent(), e.getX(), e.getY());
                    menu.setInvoker( e.getComponent() );
                }
            }
        };

        addMouseListener( ml );

        JButton button = new JButton( "Button" );
        button.setComponentPopupMenu( menu );
        //button.addMouseListener( ml );
        add(button);
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("PopupListener");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new PopupListener());
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );

        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addPropertyChangeListener("focusOwner", new PropertyChangeListener()
        {
            public void propertyChange(final PropertyChangeEvent e)
            {
                Container container = (Container)e.getNewValue();

                if (container != null
                &&  container instanceof JRootPane)
                {
                    System.out.println( "Popup Shown" );
                }
            }
        });
    }

    public static void main(String[] args)
    {
        java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}

Don't know if this is the only event that will give focus to the root pane.

So, a more complete check might be to see if a JPopupMenu component has been added to the JRootPane.

This can be done by using the Swing Utils class and replacing the above edit with:

if (container != null
&&  SwingUtils.getDescendantsOfType(JPopupMenu.class, container, true).size() != 0)
{
    System.out.println( "JPopupMenu found" );
}
camickr
  • 321,443
  • 19
  • 166
  • 288
0

This may sound esoteric, but there are a number of tools that modify Java code on the fly. Think of breakpoints or instrumentation aiming at test coverage reports or profiling.

What you might want to discover is whenever MouseEvent.isPopupTrigger() returns true, or even better whenever JPopupMenu.show() is called.

Unfortunately I have never tried something like this myself, and am wondering whether these links might contain a starting point:

Queeg
  • 7,748
  • 1
  • 16
  • 42