Java 失去焦点时无法隐藏SystemTray JPopupMenu

Java 失去焦点时无法隐藏SystemTray JPopupMenu,java,swing,system-tray,jpopupmenu,focuslistener,Java,Swing,System Tray,Jpopupmenu,Focuslistener,这个问题类似于。我拥有的是一个从系统托盘上的图标弹出的jpopumenu。此时,系统托盘是程序的唯一显示。也就是说,没有其他窗口打开,系统托盘中的图标是我访问该程序的唯一方式。我在AWTPopupMenu上使用了一个jpoppupMenu,因为我想将系统的外观应用到弹出菜单上-当我只使用一个普通的PopupMenu时,我无法获得系统的外观,我只是不断获得Swing的金属外观。我使用这种变通方法来获得这种行为(描述): 当我右键单击托盘图标时,它会显示菜单,当我进行选择时,菜单自然会消失。然而,当

这个问题类似于。我拥有的是一个从系统托盘上的图标弹出的
jpopumenu
。此时,系统托盘是程序的唯一显示。也就是说,没有其他窗口打开,系统托盘中的图标是我访问该程序的唯一方式。我在AWT
PopupMenu
上使用了一个
jpoppupMenu
,因为我想将系统的外观应用到弹出菜单上-当我只使用一个普通的
PopupMenu
时,我无法获得系统的外观,我只是不断获得Swing的金属外观。我使用这种变通方法来获得这种行为(描述):

当我右键单击托盘图标时,它会显示菜单,当我进行选择时,菜单自然会消失。然而,当我打开菜单,然后点击它,它并没有消失。要使其当前消失,我必须进行选择,或选择一个禁用的菜单项

我尝试向它添加一个
FocusListener
,但是,没有迹象表明
focusLost
focusgovered
方法曾经被调用过。此外,当另一个
窗口获得焦点时,我无法使其消失,因为没有其他窗口存在。由于此弹出菜单来自
TrayIcon
而不是典型的按钮,因此我无法使用上述解决方案绕过
FocusListener
而不调用
focusLost

最后,我想知道的是或者
1) 是否有办法获得正常AWT
PopupMenu
?或
的系统外观 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();

}