【发布时间】:2013-11-08 20:45:27
【问题描述】:
这个问题类似于this one。我所拥有的是从系统托盘上的图标弹出的JPopupMenu。此时,系统托盘是程序的唯一体现。也就是说,没有其他窗口打开,系统托盘中的图标是我访问该程序的唯一途径。我在 AWT PopupMenu 上使用了 JPopupMenu,因为我想将系统外观应用到弹出菜单 - 当我只使用普通的 PopupMenu 时,我无法获得系统的外观,我只是不断获得 Swing 的金属外观和感觉。我使用此解决方法来获得此行为(描述为here):
systemTrayPopupMenu = buildSystemTrayJPopupMenu();
trayIcon = new TrayIcon(iconImage, "Application Name", null /* Popup Menu */);
trayIcon.addMouseListener (new MouseAdapter () {
@Override
public void mouseReleased (MouseEvent me) {
if (me.isPopupTrigger()) {
systemTrayPopupMenu.setLocation(me.getX(), me.getY());
systemTrayPopupMenu.setInvoker(systemTrayPopupMenu);
systemTrayPopupMenu.setVisible(true);
}
}
};
当我右键单击托盘图标时,它会显示菜单,当我进行选择时,菜单自然会消失。但是,当我调出菜单,然后单击它时,它并没有消失。要使其当前消失,我必须进行选择,或者选择已禁用的菜单项之一。
我尝试向其中添加FocusListener,但是没有迹象表明focusLost 或focusGained 方法会被调用。此外,当另一个Window 获得焦点时,我不能让它消失,因为没有其他窗口存在。由于此弹出菜单来自TrayIcon 而不是典型按钮,因此我无法使用提到的here 解决方案来绕过FocusListener 不调用focusLost。
最终,我想知道的是要么:
1) 有没有办法获得正常 AWT PopupMenu 的系统外观和感觉?,或
2)有没有办法让JPopupMenu在失去焦点时消失?
编辑:根据要求,这是我的SSCCE:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SwingSystemTray {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run () {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new SwingSystemTray ();
} catch (Exception e) {
System.out.println("Not using the System UI defeats the purpose...");
e.printStackTrace();
}
}
});
}
protected SystemTray systemTray;
protected TrayIcon trayIcon;
protected JPopupMenu systemTrayPopupMenu;
protected Image iconImage;
public SwingSystemTray () throws IOException {
iconImage = getIcon ();
if (SystemTray.isSupported()) {
systemTray = SystemTray.getSystemTray();
systemTrayPopupMenu = buildSystemTrayJPopupMenu();
trayIcon = new TrayIcon(iconImage, "Application Name", null /* Popup Menu */);
trayIcon.addMouseListener (new MouseAdapter () {
@Override
public void mouseReleased (MouseEvent me) {
if (me.isPopupTrigger()) {
systemTrayPopupMenu.setLocation(me.getX(), me.getY());
systemTrayPopupMenu.setInvoker(systemTrayPopupMenu);
systemTrayPopupMenu.setVisible(true);
}
}
});
try {
systemTray.add(trayIcon);
} catch (AWTException e) {
System.out.println("Could not place item at tray. Exiting.");
}
}
}
protected JPopupMenu buildSystemTrayJPopupMenu () {
final JPopupMenu menu = new JPopupMenu ();
final JMenuItem showMenuItem = new JMenuItem("Show");
final JMenuItem hideMenuItem = new JMenuItem("Hide");
final JMenuItem exitMenuItem = new JMenuItem("Exit");
hideMenuItem.setEnabled(false);
ActionListener listener = new ActionListener () {
@Override
public void actionPerformed (ActionEvent ae) {
Object source = ae.getSource();
if (source == showMenuItem) {
System.out.println("Shown");
showMenuItem.setEnabled(false);
hideMenuItem.setEnabled(true);
}
else if (source == hideMenuItem) {
System.out.println("Hidden");
hideMenuItem.setEnabled(false);
showMenuItem.setEnabled(true);
}
else if (source == exitMenuItem) {
System.exit(0);
}
}
};
for (JMenuItem item : new JMenuItem [] {showMenuItem, hideMenuItem, exitMenuItem}) {
if (item == exitMenuItem) menu.addSeparator();
menu.add(item);
item.addActionListener(listener);
}
return menu;
}
protected Image getIcon () throws IOException {
// Build the 16x16 image programmatically, start with BMP Header
byte [] iconData = new byte[822];
System.arraycopy(new byte [] {0x42,0x4d,0x36,0x03, 0,0,0,0, 0,0,0x36,0,
0,0,0x28,0, 0,0,16,0, 0,0,16,0, 0,0,16,0, 24,0,0,0, 0,0,0,3},
0, iconData, 0, 36);
for (int i = 36; i < 822; iconData[i++] = 0);
for (int i = 56; i < 822; i += 3) iconData[i] = -1;
return ImageIO.read(new java.io.ByteArrayInputStream(iconData));
}
}
【问题讨论】:
-
这实际上是许多托盘图标的问题......因为他们没有父焦点的概念来知道焦点何时实际改变。我见过的最好的解决方案是简单地在菜单末尾放置一个“关闭”选项并让用户关闭它;)。我没试过,但我也想过给转义键添加一个键绑定......
-
发布您的
SSCCE来证明问题。
标签: java swing system-tray jpopupmenu focuslistener