United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6515446 JMenuItems in JPopupMenus not receiving ActionEvents - incompat with 1.5
JDK-6515446 : JMenuItems in JPopupMenus not receiving ActionEvents - incompat with 1.5

Details
Type:
Bug
Submit Date:
2007-01-19
Status:
Resolved
Updated Date:
2011-01-19
Project Name:
JDK
Resolved Date:
2007-04-12
Component:
client-libs
OS:
windows_xp
Sub-Component:
javax.swing
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:
6u2 (b02)

Related Reports
Backport:
Relates:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
JMenuItems in JPopupMenus do not seem to be receiving ActionEvents when the mouse button is released over the item.  This is incompatible with 1.5.0_10, in which an ActionEvent is received..

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached program.  Right or left click in the middle of the frame. Select the item from the popup that appears.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The button text should be displayed in the lower left corner.  This is what happens under 1.5.0_10.
ACTUAL -
The text is not displayed under 1.6.0.

Note that if you select the item from the menu in the menu bar, the text is always displayed under both versions.  It is only with popups that the anomaly occurs.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.*;

import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JPopupMenu;
import javax.swing.JPanel;
import javax.swing.JFrame;

public class PopupDemo extends JPanel implements ActionListener, MouseListener {
   private static final long serialVersionUID = 1L;
   JPopupMenu popup = new JPopupMenu();
   JLabel messageArea = new JLabel();

   public static void main(String[] args) {
      new PopupDemo();
   }

   public PopupDemo() {
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("menu");
      menuBar.add(menu);
      JMenuItem menuItem = new JMenuItem("menu item");
      menuItem.addActionListener(this);
      menu.add(menuItem);
      
      menuItem = new JMenuItem("popup item");
      menuItem.addActionListener(this);
      popup.add(menuItem);
      
      addMouseListener(this);
      setPreferredSize(new Dimension(200, 200));
      frame.setJMenuBar(menuBar);
      frame.add(this,BorderLayout.CENTER);
      frame.add(messageArea,BorderLayout.SOUTH);
      frame.pack();
      frame.setLocation(200, 200);
      frame.setVisible(true);
   }

   public void actionPerformed(ActionEvent e) {
      messageArea.setText(e.getActionCommand());
   }
   public void mousePressed(MouseEvent e) {
      messageArea.setText("");
      popup.show(this,e.getX(),e.getY());
   }
   public void mouseReleased(MouseEvent e) {
      popup.setVisible(false);
   }
   public void mouseClicked(MouseEvent e) {}
   public void mouseEntered(MouseEvent e) {}
   public void mouseExited(MouseEvent e) {}
}

---------- END SOURCE ----------

Release Regression From : 5
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

Release Regression From : 5
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

                                    

Comments
WORK AROUND

Calculate the location of the popup menu and call action performed from the mouseRelease if mouse cursor is released within the popup menu area.

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.*;

import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JPopupMenu;
import javax.swing.JPanel;
import javax.swing.JFrame;

public class PopupDemo extends JPanel implements ActionListener,
MouseListener {
   private static final long serialVersionUID = 1L;
   JPopupMenu popup = new JPopupMenu();
   JLabel messageArea = new JLabel();

   public static void main(String[] args) {
      new PopupDemo();
   }

   public PopupDemo() {
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("menu");
      menuBar.add(menu);
      JMenuItem menuItem = new JMenuItem("menu item");
      menuItem.addActionListener(this);
      menu.add(menuItem);
      
      PopupMenuItem popupMenuItem = new PopupMenuItem("popup item 1");
      popupMenuItem.addActionListener(this);
      popup.add(popupMenuItem);
      popupMenuItem = new PopupMenuItem("popup item 2");
      popupMenuItem.addActionListener(this);
      popup.add(popupMenuItem);
      popupMenuItem = new PopupMenuItem("popup item 3");
      popupMenuItem.addActionListener(this);
      popup.add(popupMenuItem);
      
      addMouseListener(this);
      setPreferredSize(new Dimension(200, 200));
      frame.setJMenuBar(menuBar);
      frame.add(this,BorderLayout.CENTER);
      frame.add(messageArea,BorderLayout.SOUTH);
      frame.pack();
      frame.setLocation(200, 200);
      frame.setVisible(true);
   }
   
   Point popupLoc;

   public void actionPerformed(ActionEvent e) {
      messageArea.setText(e.getActionCommand());
   }
   public void mousePressed(MouseEvent e) {
      messageArea.setText("");
      popupLoc = new Point(e.getX(), e.getY());
      popup.show(this, e.getX(), e.getY());
   }
   public void mouseReleased(MouseEvent e) {
      Component[] popupMenuItems = popup.getComponents();
      for (Component c : popupMenuItems) {
         Point itemLoc = c.getLocation();
         if (c.contains(e.getX() - itemLoc.x - popupLoc.x, e.getY() -
itemLoc.y - popupLoc.y)) {
            ((PopupMenuItem)c).fireActionPerformed();
            break;
         }
      }
      popup.setVisible(false);
   }
   public void mouseClicked(MouseEvent e) {}
   public void mouseEntered(MouseEvent e) {}
   public void mouseExited(MouseEvent e) {}
}

class PopupMenuItem extends JMenuItem {
   private static final long serialVersionUID = 1L;
   
   public PopupMenuItem(String text) {
      super(text);
   }
   
   public void fireActionPerformed() {
      fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
getActionCommand()));
   }
}
                                     
2007-01-26
EVALUATION

This is a side-effect of the fix for 5036146
which skips the mouseReleased events for a menu
if invoker is not a MenuElement
(see the suggested fix)

I am not sure it is possible to fix this regressing without breaking 
the fix for the 5036146
                                     
2007-03-12
WORK AROUND

another workaround is to make a panel implement MenuElement interface
with just empty methods
                                     
2007-03-20
EVALUATION

After thoroughly testing it becomes clear that this is a serious bug
and we should fix it ASAP

I tested this testcase together with ones from 6415145 and 5036146
and think it is possible to fix this one without breaking the others

the idea is to add the

if (isInPopup(src)) {
     break;
}

checking to the MouseEvent.MOUSE_RELEASED: case of the MouseGrabber,
it is actually the same what we have already done for the MOUSE_DRAGGED case

More testing will be done
                                     
2007-03-21



Hardware and Software, Engineered to Work Together