2 Replies Latest reply on Jan 29, 2005 4:06 PM by 843804

    Can popup menu events be consumed by other (e.g. background) components?

    843804
      Has anyone seen where popup menu events seem to not get directed to the component that you think should receive them (i.e. foreground components)?

      The class below is a test case that you should be able to compile and run which I believe demonstrates this phenomena. The class's javadocs thoroughly explain my test procedure. By the way, you will need JDK 1.5+ in order to compile and run this, since I use the new JComponent methods setComponentPopupMenu and setInheritsPopupMenu (if you are unfamiliar with this, see the excellent article http://www-106.ibm.com/developerworks/library/j-tiger05124/?ca=dnt-522).

      The important point is that, at least on my machine, no matter where you click inside the JFrame, no popup menu appears except when you right click over the JTextArea. But I would have thought that a popup menu should always appear, regardless of where inside the JFrame that I right click. I am particularly puzzled as to why the JLabel, which is treated the same as the JTextArea, fails to get popup menu events.

      My interpretation is that this must be because some other (background) component consumed the popup event before it can reach my components which have associated popup menus.

      Or am I just not understanding how to use the popup menu api?

      Or is the new setComponentPopupMenu and setInheritsPopupMenu functionality buggy?
      import java.awt.Color;
      
      import javax.swing.*;
      import javax.swing.event.*;
      
      
      /**
      * This class bring up a new JFrame whose ContentPane contains
      * a new JPanel which contains
      * a new JLabel and a new JTextArea.
      * <p>
      * The JFrame's content pane's background is set to red, and the JPanel's background is set to green,
      * so that you can visually see everywhere each extends.
      * (As expected, the JPanel fills the entirety of the inside of the JFRame.)
      * <p>
      * Dedicated JPopupMenu instances are assigned to all of the JFrame's panes (content, glass, layered, and root)
      * as well as the JPanel.
      * The JLabel and JTextArea are assigned to inherit their PopupMenu,
      * which here means that they will use the JPanel's PopupMenu.
      * <p>
      * The popup menus all contain just a single item whoch does nothing except state the source of the popup event.
      * A given popup menu instance also has an associated PopupMenuListener which prints events to System.out,
      * identifying the event source in the process,
      * so that if it was generated but was somehow obscured, then you can tell from looking at System.out.
      * <p>
      * The expected outcome of running this class is that you should be able to mouse right click
      * (this assumes Windoze is the OS) anywhere inside the JFrame and a popup menu should appear.
      * More specifically, that popup menu should always have a single item labeled "Event from JPanel"
      * because the JPanel fills up all the inside of the JFrame
      * and all of its children inherit their popup menu from it.
      * <p>
      * What happens in reality is different:
      * if you right click directly over the JTextArea, the expected popup menu appears,
      * but if you right click over anywhere else (e.g. directly over the JLabel), nothing appears.
      * <p>
      * What must be happening is that some other component is first receiving many of the mouse events and consuming them.
      * <p>
      * @author Brent Boyer
      * @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4465870">A possibly related bug report</a>
      */
      public class PopupMenuBug {
           
       
           public static void main(String[] args) throws Exception {
                buildGui();
           }
           
       
           private static void buildGui() {
                JFrame frame = new JFrame();
                frame.setSize(600, 500);
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.getContentPane().setBackground( Color.RED );
                
                ((JComponent) frame.getContentPane()).setComponentPopupMenu( new PopupMenuLabeled("Event from ContentPane") );
                ((JComponent) frame.getGlassPane()).setComponentPopupMenu( new PopupMenuLabeled("Event from GlassPane") );          
                frame.getLayeredPane().setComponentPopupMenu( new PopupMenuLabeled("Event from LayeredPane") );
                frame.getRootPane().setComponentPopupMenu( new PopupMenuLabeled("Event from RootPane") );
                
                frame.getContentPane().add( buildItems() );
      
                frame.setVisible(true);
           }
           
       
           private static JComponent buildItems() {
                JPanel jpanel = new JPanel();
                jpanel.setBackground( Color.GREEN );
                jpanel.setComponentPopupMenu( new PopupMenuLabeled("Event from JPanel") );
                          
                jpanel.add( buildItem1() );
                jpanel.add( Box.createHorizontalStrut(20) );
                jpanel.add( buildItem2() );
                
                return jpanel;
           }
           
       
           private static JComponent buildItem1() {
                JLabel label = new JLabel("Label");
                label.setInheritsPopupMenu(true);
                return label;
           }
           
       
           private static JComponent buildItem2() {
                JTextArea textArea = new JTextArea("JTextArea", 20, 20);
                textArea.setInheritsPopupMenu(true);
                return textArea;
           }
           
           
           private static class PopupMenuLabeled extends JPopupMenu {
                private static final long serialVersionUID = 1;
                
                private PopupMenuLabeled(final String label) {
                     add( new JMenuItem( label ) );
                     
                     addPopupMenuListener( new PopupMenuListener() {
                          public void popupMenuWillBecomeVisible(PopupMenuEvent e) { System.out.println( label + ": popupMenuWillBecomeVisible" ); }
                          public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { System.out.println( label + ": popupMenuWillBecomeInvisible" + "\n" ); }
                          public void popupMenuCanceled(PopupMenuEvent e) { System.out.println( label + ": popupMenuCanceled" ); }
                     } ); 
                }
           }
      
      
      }
        • 1. Re: Can popup menu events be consumed by other (e.g. background) components
          843804
          I'm not quite sure about this, but I think it might have to do with the fact that JPanels and JLabels per default don't care about mouse events. I ran your code, but instead of creating a standard JLabel I created a customized label:
               private static class MyLabel extends JLabel {
                   public MyLabel(String s) {
                       super(s);
                          // Enable mouse events to be delivered to this component.
                       enableEvents(AWTEvent.MOUSE_EVENT_MASK);
                   }
               }
          and then the popup menu will appear when you right-click on the label.

          Another way of enabling mouse events on a JLabel would be to just add an empty MouseListener to it.:
                    JLabel label = new JLabel("Label");
                    label.addMouseListener( new MouseAdapter() {} );
          That will have the same effect as the call to enableEvents.

          Again, I'm not completely sure about this (other than that it seems to work :-).
          • 2. Re: Can popup menu events be consumed by other (e.g. background) components
            843804
            I'm not quite sure about this, but I think it might have to do with the fact that JPanels and JLabels per default don't care about mouse events
            Yes, your intuition is correct; someone else (thank you Mr Zukowski) pointed out to me the following bug:

            http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4966109

            Both of your workarounds to this bug will do the trick -- thanks very much! -- but we should not have to do this. I am shocked that Sun chose to design swing with lightweight components not being interested in mouse events.