FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Darwin Rainers-MBP-2.home 15.2.0 Darwin Kernel Version 15.2.0: Fri Nov 13 19:56:56 PST 2015; root:xnu-3248.20.55~2/RELEASE_X86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
It seems to be impossible to update the popup menu of a TrayIcon, see attached sample program.
This issue might be related to JDK-8007220 but while the test program there works as expected, this current bug is still visible.
This bug does not seem to appear on Windows.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. create a TrayIcon with a popup menu
2. upon some event (e.g. MenuItem action) update the popup menu
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the popup menu should be updated
ACTUAL -
the initially set popup menu is still visible
ERROR MESSAGES/STACK TRACES THAT OCCUR :
no error is shown
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
public class TrayIconBug {
/**
* This class demostrates a bug in the TrayIcon class in which
* updates to a TrayIcons PopupMenu added to a SystemTray do not take effect.
* <p>
* The issue might be related to JDK-8007220 but affects all JDK versions even if they pass the test with the sample
* application.
*/
private static final String bugId = "1";
private static final String applicationName = "TrayIconBug" + bugId;
private static int trayIconImageSize = 32;
private static int trayIconImageInset = 4;
/**
* Create a small image of a green/red circle to use as the icon for the tray icon
*
* @param addSystemTrayBeforeMenuItemsAreAdded if true, a red cirle is returned. If false, a green circle is returned
* @return the Image created
*/
private static Image createTrayIconImage(final boolean addSystemTrayBeforeMenuItemsAreAdded) {
/**
* Create a small image of a red circle to use as the icon for the tray icon
*/
final BufferedImage trayImage = new BufferedImage(trayIconImageSize, trayIconImageSize, BufferedImage.TYPE_INT_ARGB);
final Graphics2D trayImageGraphics = (Graphics2D) trayImage.getGraphics();
trayImageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
trayImageGraphics.setColor(new Color(255, 255, 255, 0));
trayImageGraphics.fillRect(0, 0, trayImage.getWidth(), trayImage.getHeight());
if (addSystemTrayBeforeMenuItemsAreAdded) {
trayImageGraphics.setColor(Color.red);
} else {
trayImageGraphics.setColor(Color.green);
}
trayImageGraphics.fillOval
(trayIconImageInset,
trayIconImageInset,
trayImage.getWidth() - 2 * trayIconImageInset,
trayImage.getHeight() - 2 * trayIconImageInset);
trayImageGraphics.setColor(Color.darkGray);
trayImageGraphics.drawOval
(trayIconImageInset,
trayIconImageInset,
trayImage.getWidth() - 2 * trayIconImageInset,
trayImage.getHeight() - 2 * trayIconImageInset);
return trayImage;
}
private static PopupMenu createTrayIconPopupMenu(TrayIcon trayIcon) {
return createTrayIconPopupMenu(trayIcon, 2);
}
/**
* Create popup menu for system tray. Creates a popup menu like:
* <p>
* Menu Item 1
* Menu Item 2
* Sub menu
* Submenu Item 1
* Submenu Item 2
* <p>
* In addition, if a menu item (Menu Item 1 or 2) is clicked, it *should* update the menu to have 3 menu items
* (etc.).
* </p>
*
* @return the PopupMenu created
*/
private static PopupMenu createTrayIconPopupMenu(final TrayIcon trayIcon, final int menuCount) {
final PopupMenu trayIconPopupMenu = new PopupMenu();
for (int i = 1; i <= menuCount; i++) {
final String popupMenuItemText = "Menu Item " + i;
final MenuItem popupMenuItem = new MenuItem(popupMenuItemText);
popupMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
System.out.println(popupMenuItemText + " action listener called, updating popup menu to have "
+ (menuCount + 1) + " elements...");
trayIcon.setPopupMenu(createTrayIconPopupMenu(trayIcon, menuCount + 1));
}
});
trayIconPopupMenu.add(popupMenuItem);
}
final PopupMenu popupSubMenu = new PopupMenu("Submenu");
for (int i = 1; i <= 2; i++) {
final String popupMenuItemText = "Submenu Item " + i;
final MenuItem popupMenuItem = new MenuItem(popupMenuItemText);
popupMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
System.out.println(popupMenuItemText + " action listener called...");
}
});
popupSubMenu.add(popupMenuItem);
}
trayIconPopupMenu.add(popupSubMenu);
return trayIconPopupMenu;
}
private static void createSystemTrayIcons() {
/**
* Create a tray icon with two submenus: "Menu item 1" & "Menu item 2". This tray icon
* is visible in the status bar on Mac OS X as a green. Clicking Menu Item 1 or 2 will try to
* set a new popup menu with 3 menu items, if everything works, clicking one of the 3 menu items will add
* yet one more.
*/
final TrayIcon trayIcon = new TrayIcon(createTrayIconImage(true));
trayIcon.setImageAutoSize(true);
trayIcon.setToolTip(applicationName + " system tray");
try {
// Add tray icon action listenr for logging clicks on the tray icon
trayIcon.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
System.out.println("Tray icon action listener called...");
}
});
trayIcon.setPopupMenu(createTrayIconPopupMenu(trayIcon));
// Add tray icon to system tray
SystemTray.getSystemTray().add(trayIcon);
} catch (final AWTException awte) {
awte.printStackTrace();
}
}
private static void createFrame() {
/**
* Create a small window on the screen to make the application visible
* to the user. A small explanation is included in the window shown.
*
* Clicking the close button of the window quits the application
*/
final JPanel panel = new JPanel();
panel.setBorder(new CompoundBorder(panel.getBorder(), new EmptyBorder(15, 15, 15, 15)));
panel.setLayout(new BorderLayout());
panel.add(new JLabel(applicationName + " demo application"), BorderLayout.NORTH);
panel.add(new JLabel("Click one of the top level menu items to set a new popup menu with 3 menu items."), BorderLayout.CENTER);
final JFrame frame = new JFrame(applicationName + " information");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.add(panel);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(final WindowEvent we) {
System.exit(0);
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (SystemTray.isSupported()) {
createSystemTrayIcons();
createFrame();
}
}
});
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
there doesn't seem to be a workaround. If there is one I would be very interested.