Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6536033

JPopupMenu and TrayIcon ClassCastException

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P4
    • Resolution: Duplicate
    • Affects Version/s: 6
    • Fix Version/s: None
    • Component/s: client-libs
    • Labels:

      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)java version

      "1.6.0_01"
      Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
      Java HotSpot(TM) Server VM (build 1.6.0_01-b06, mixed mode)

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

      A DESCRIPTION OF THE PROBLEM :
      Using the java.awt.TrayIcon's "setPopupMenu" method expects an AWT popup menu. However, the AWT menu does not match the native OS popup menu appearance (large arial font instead of smaller tahoma font on my windows desktop), so I attempted to use a JPopupMenu instead (worked nicely with JDIC), according to this blog entry:
      http://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html

      This works fine the first time it's rendered, but all subsequent attempts to right-click the tray icon provoke a ClassCastException. This looks like:
      http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6309495 ("JMenuItem and TrayIcon does not work when in same application")
      ...but is different. Looking at the source code referred to by my stack trace, it would almost certainly appear to be the same *type* of error, but in a different block of code.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Please refer to http://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html which has a straightforward example. Bear in mind that the first attempt seems okay, it's thereafter that it fails.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      A JPopupMenu is displayed for the TrayIcon everytime it's right-clicked.
      ACTUAL -
      It is only displayed the first time. All subsequent requests fail.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.awt.TrayIcon cannot be cast to java.awt.Component
      at javax.swing.plaf.basic.BasicPopupMenuUI$MouseGrabber.eventDispatched(BasicPopupMenuUI.java:796)
      at java.awt.Toolkit$SelectiveAWTEventListener.eventDispatched(Toolkit.java:2360)
      at java.awt.Toolkit$ToolkitEventMulticaster.eventDispatched(Toolkit.java:2252)
      at java.awt.Toolkit.notifyAWTEventListeners(Toolkit.java:2210)
      at java.awt.TrayIcon.dispatchEvent(TrayIcon.java:689)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:604)
      at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
      at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
      at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
      at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------

      import java.awt.AWTException;
      import java.awt.Color;
      import java.awt.Graphics2D;
      import java.awt.SystemTray;
      import java.awt.TrayIcon;
      import java.awt.RenderingHints;
      import java.awt.BasicStroke;
      import java.awt.geom.Path2D;
      import java.awt.event.MouseAdapter;
      import java.awt.event.MouseEvent;
      import java.awt.event.WindowAdapter;
      import java.awt.event.WindowEvent;
      import java.awt.image.BufferedImage;
      import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JMenuItem;
      import javax.swing.JOptionPane;
      import javax.swing.JPopupMenu;
      import javax.swing.SwingUtilities;
      import javax.swing.BorderFactory;



      public class Incident926606
      {
          private Incident926606() {}

          public static void main(String[] args)
          {
              SwingUtilities.invokeLater(new Runnable(){
                  public void run() { createAndShowGUI(); }
              });
          }

          private static void createAndShowGUI()
          {
              if (!SystemTray.isSupported())
              {
                  JOptionPane.showMessageDialog(null,
                      "SystemTray is not supported",
                      "Incident926606",
                      JOptionPane.ERROR_MESSAGE);
                  return;
              }

              // draw an icon
              BufferedImage icon = new BufferedImage(16,16,TYPE_INT_ARGB);
              Graphics2D g2d = icon.createGraphics();
              Path2D.Float path = new Path2D.Float(Path2D.WIND_NON_ZERO);
              path.moveTo(0,1);
              path.lineTo(14,8);
              path.lineTo(0,14);
              path.closePath();
              g2d.setColor(Color.BLUE);
              g2d.fillRect(0,0,icon.getWidth(),icon.getHeight());
              g2d.setRenderingHint(
                  RenderingHints.KEY_ANTIALIASING,
                  RenderingHints.VALUE_ANTIALIAS_ON
              );
              g2d.setColor(Color.YELLOW);
              g2d.fill(path);
              g2d.setColor(Color.WHITE);
              g2d.setStroke(new BasicStroke(2));
              g2d.draw(path);
              g2d.dispose();

              // make a swing popup menu
              // then bind it to mouse events
              // we're doing this because awt popup doesn't match native equivalent
              final JPopupMenu popup = new JPopupMenu();
              for (int i = 1; i <= 5; i++)
              {
                  popup.add(new JMenuItem("Mock option "+i));
              }
              final TrayIcon trayIcon = new TrayIcon(icon);
              trayIcon.addMouseListener(new MouseAdapter(){
                  private void maybeShowPopup(MouseEvent evt)
                  {
                      if (evt.isPopupTrigger())
                      {
                          popup.setLocation(evt.getX(),evt.getY());
                          popup.setInvoker(popup);
                          popup.setVisible(true);
                      }
                  }
                  @Override
                  public void mousePressed(MouseEvent evt)
                  {
                      maybeShowPopup(evt);
                  }
                  @Override
                  public void mouseReleased(MouseEvent evt)
                  {
                      maybeShowPopup(evt);
                  }
              });

              try
              {
                  SystemTray.getSystemTray().add(trayIcon);
              }
              catch (AWTException e)
              {
                  JOptionPane.showMessageDialog(null,
                      e.toString(),
                      "Incident926606",
                      JOptionPane.ERROR_MESSAGE);
                  return;
              }

              JLabel label = new JLabel("<html><body>" +
                  "Right-click tray icon twice.<br>" +
                  "First time, you'll see a JPopupMenu.<br>" +
                  "Second time, it'll crash (watch STDOUT).<br>" +
                  "If you select an option the first time,<br>" +
                  "you won't see a problem." +
                  "</body></html>"
              );
              label.setBorder(BorderFactory.createEmptyBorder(14,14,14,14));

              JFrame frame = new JFrame("Incident926606");
              frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
              frame.setIconImage(icon);
              frame.add(label);
              frame.pack();
              frame.setLocationRelativeTo(null);
              frame.addWindowListener(new WindowAdapter(){
                  @Override
                  public void windowClosing(WindowEvent evt)
                  {
                      SystemTray.getSystemTray().remove(trayIcon);
                      System.exit(0);
                  }
              });
              frame.setVisible(true);
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Use an AWT popup menu. But it's really ugly and doesn't fit in at all. I have in the past used JDIC but that project is apparently dead.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                ryeung Roger Yeung (Inactive)
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Imported:
                  Indexed: