Java 失去焦点时无法隐藏SystemTray JPopupMenu
这个问题类似于。我拥有的是一个从系统托盘上的图标弹出的Java 失去焦点时无法隐藏SystemTray JPopupMenu,java,swing,system-tray,jpopupmenu,focuslistener,Java,Swing,System Tray,Jpopupmenu,Focuslistener,这个问题类似于。我拥有的是一个从系统托盘上的图标弹出的jpopumenu。此时,系统托盘是程序的唯一显示。也就是说,没有其他窗口打开,系统托盘中的图标是我访问该程序的唯一方式。我在AWTPopupMenu上使用了一个jpoppupMenu,因为我想将系统的外观应用到弹出菜单上-当我只使用一个普通的PopupMenu时,我无法获得系统的外观,我只是不断获得Swing的金属外观。我使用这种变通方法来获得这种行为(描述): 当我右键单击托盘图标时,它会显示菜单,当我进行选择时,菜单自然会消失。然而,当
jpopumenu
。此时,系统托盘是程序的唯一显示。也就是说,没有其他窗口打开,系统托盘中的图标是我访问该程序的唯一方式。我在AWTPopupMenu
上使用了一个jpoppupMenu
,因为我想将系统的外观应用到弹出菜单上-当我只使用一个普通的PopupMenu
时,我无法获得系统的外观,我只是不断获得Swing的金属外观。我使用这种变通方法来获得这种行为(描述):
当我右键单击托盘图标时,它会显示菜单,当我进行选择时,菜单自然会消失。然而,当我打开菜单,然后点击它,它并没有消失。要使其当前消失,我必须进行选择,或选择一个禁用的菜单项
我尝试向它添加一个FocusListener
,但是,没有迹象表明focusLost
或focusgovered
方法曾经被调用过。此外,当另一个窗口获得焦点时,我无法使其消失,因为没有其他窗口存在。由于此弹出菜单来自TrayIcon
而不是典型的按钮,因此我无法使用上述解决方案绕过FocusListener
而不调用focusLost
最后,我想知道的是或者:
1) 是否有办法获得正常AWTPopupMenu
?或
的系统外观
2) 有没有办法使jpopmpmenu
在失去焦点时消失
编辑:根据请求,这里是我的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));
}
}
import java.awt.*;
导入java.awt.event.*;
导入java.io.IOException;
导入javax.imageio.imageio;
导入javax.swing.*;
公共类SwingSystemTray{
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开作废运行(){
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
新的SwingSystemTray();
}捕获(例外e){
System.out.println(“不使用系统UI会破坏目的…”);
e、 printStackTrace();
}
}
});
}
受保护的系统托盘系统托盘;
受保护的TrayIcon TrayIcon;
受保护的JPOppMenu SystemTraypOppMenu;
图像图像保护;
公共SwingSystemTray()引发IOException{
iconImage=getIcon();
if(SystemTray.issuported()){
systemTray=systemTray.getSystemTray();
systemTrayPopupMenu=buildSystemTrayJPPopupMenu();
trayIcon=新trayIcon(图标,“应用程序名称”,null/*弹出菜单*/);
trayIcon.addMouseListener(新的MouseAdapter(){
@凌驾
公共无效MouseEvent me(MouseEvent me){
if(me.isPopupTrigger()){
systemTrayPopupMenu.setLocation(me.getX(),me.getY());
setInvoker(systemTrayPopupMenu);
systemTrayPopupMenu.setVisible(真);
}
}
});
试一试{
systemTray.add(trayIcon);
}捕获(awtexe){
System.out.println(“无法在托盘上放置项目。正在退出”);
}
}
}
受保护的JPOppMenu BuildSystemTrayJPOppMenu(){
最终JPopupMenu菜单=新的JPopupMenu();
最终JMenuItem showMenuItem=新JMenuItem(“显示”);
最终JMenuItem hideMenuItem=新JMenuItem(“隐藏”);
最终JMenuItem exitMenuItem=新JMenuItem(“退出”);
hideMenuItem.setEnabled(false);
ActionListener=新的ActionListener(){
@凌驾
已执行的公共无效行动(行动事件ae){
Object source=ae.getSource();
如果(源==showMenuItem){
系统输出打印项次(“显示”);
showMenuItem.setEnabled(false);
hideMenuItem.setEnabled(真);
}
else if(source==hideMenuItem){
System.out.println(“隐藏”);
hideMenuItem.setEnabled(false);
showMenuItem.setEnabled(true);
}
else if(source==exitMenuItem){
系统出口(0);
}
}
};
对于(JMenuItem项:新JMenuItem[]{showMenuItem、hideMenuItem、exitMenuItem}){
if(item==exitMenuItem)菜单.addSeparator();
菜单。添加(项目);
item.addActionListener(listener);
}
返回菜单;
}
受保护的图像getIcon()引发IOException{
//以编程方式构建16x16图像,从BMP头开始
字节[]iconData=新字节[822];
数组复制(新字节[]{0x42,0x4d,0x36,0x03,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,0,3},
0,Iconda,0,36);
对于(int i=36;i<822;i数据[i++]=0);
对于(int i=56;i<822;i+=3)i数据[i]=-1;
返回ImageIO.read(新的java.io.ByteArrayInputStream(IConda));
}
}
一个JPopupMenu不能单独显示。也就是说,它需要添加到窗口中。尝试使用WindowListener,然后隐藏windowDeactivated()事件的弹出窗口。在弹出窗口可见后,您应该能够通过以下方式获取窗口:
Window window = SwingUtilities.windowForComonent(systemTrayPopupMenu);
我发现了一个我觉得会很好用的方法。我还没有在WindowsXP中测试它,但它在Windows7中工作。这涉及到添加一个显示在弹出菜单后面的“隐藏对话框”,就像弹出菜单最初源自隐藏对话框一样。唯一真正的诀窍是让隐藏的对话框留在弹出菜单后面。至少在Windows7中,它显示在系统托盘的后面,因此您永远不会真正看到它
Window window = SwingUtilities.windowForComonent(systemTrayPopupMenu);
package org.test;
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 {
/* We are going for the Windows Look and Feel here */
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;
/* Added a "hidden dialog" */
protected JDialog hiddenDialog;
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());
/* Place the hidden dialog at the same location */
hiddenDialog.setLocation(me.getX(), me.getY());
/* Now the popup menu's invoker is the hidden dialog */
systemTrayPopupMenu.setInvoker(hiddenDialog);
hiddenDialog.setVisible(true);
systemTrayPopupMenu.setVisible(true);
}
}
});
trayIcon.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent ae) {
System.out.println("actionPerformed");
}
});
try {
systemTray.add(trayIcon);
} catch (AWTException e) {
System.out.println("Could not place item at tray. Exiting.");
}
}
/* Initialize the hidden dialog as a headless, titleless dialog window */
hiddenDialog = new JDialog ();
hiddenDialog.setSize(10, 10);
/* Add the window focus listener to the hidden dialog */
hiddenDialog.addWindowFocusListener(new WindowFocusListener () {
@Override
public void windowLostFocus (WindowEvent we ) {
hiddenDialog.setVisible(false);
}
@Override
public void windowGainedFocus (WindowEvent we) {}
});
}
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) {
/* We want to make sure the hidden dialog goes away after selection */
hiddenDialog.setVisible(false);
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));
}
}
@Override
public void mouseEntered(MouseEvent arg0) {
mouseStillOnMenu = true;
}
@Override
public void mouseExited(MouseEvent arg0) {
mouseStillOnMenu = false;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000); //waits one second before checking if mouse is still on the menu
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (!isMouseStillOnMenu()) {
jpopup.setVisible(false);
}
}
}).start();
}