TrayIcon构造函数
方法 |
描述 |
TrayIcon(Image image) |
Creates a TrayIcon with the specified image. |
TrayIcon(Image image, String tooltip) |
Creates a TrayIcon with the specified image and tooltip text. |
TrayIcon(Image image, String tooltip, PopupMenu popup) |
Creates a TrayIcon with the specified image, tooltip and popup menu. |
可以看到,我们可以使用PopupMenu
作为系统托盘程序的弹出菜单。
但是PopupMenu有如下问题:
- PopupMenu添加的菜单项MenuItem不支持图标,是awt级组件,没有提供paint函数,也就意味着不能重绘,去实现带图标的菜单;
- PopupMenu只支持英文,中文会乱码,如果确实需要支持中文的话,运行的jar时候,需要使用加上
-Dfile.encoding=GBK
参数,指定以GBK编码来运行,一般来说我们要处理的文件也通常是UTF-8编码的,如果使用这个GBK编码运行的jar来处理此文件,就会出现乱码问题。
JPopupMenu是Swing组件,而且支持图标+文本,更美观。在标准API里,添加JPopupMenu的有两种方式:
1、Component组件调用setComponentPopuMenu(JPopupMenu)方法来绑定JPopupMenu;
2、JPopupMneu调用show(Component c,int x,int y)方法绑定至组件的(x,y)坐标上;
但问题是,TrayIcon不是Component,不能通过上述两种方法进行绑定。
弹出菜单的触发过程
在 鼠标点击或者按下快捷键 时 生成弹出菜单。
所以我们可以在点击系统托盘的时候,单独创建一个Component作为JPopupMenu的参考坐标。
这个Component,我们可选择Java现成的JWindow或者JDialog等等。经过测试JDialog来实现会更好一些。
获取鼠标点击的坐标值,在这个坐标值上创建一个JDialog,然后将JPopupMenu绑定到这个JDialog的(0,0)位置上,弹出菜单显示后再获取弹出菜单的尺寸,再根据尺寸回调JDialog的大小,这样JPopupMenu就完美的遮罩了JDialog,看不出JDialog的存在。
不过这样做,还有最后一个问题,那就是在弹出菜单消失后,JDialog依然存在;
这倒不用担心,JPopupMenu提供了:firePopupMenuCanceled()、firePopupMenuWillBecomeInvisible()、firePopupMenuWillBecomeVisible(),菜单消失、消失前、消失后,这三个回调函数。
所以,我们可以选择重写其中任意一个函数,在JPopupMenu消失之前关闭JPopupMenu的载体即可。
这样就可以完美实现系统托盘弹出菜单啦。
demo
项目结构
1 2 3 4 5 6 7
| G:\dev2\idea_workspace\MyJavaTools\RunableTools └─src\ ├─demo\ │ └─ui\ │ ├─SystemTrayCH.java │ └─SystemTrayEn.java └─工具_16.png
|
工具_16.png
SystemTrayEn.java
G:\dev2\idea_workspace\MyJavaTools\RunableTools\src\demo\ui\SystemTrayEn.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package demo.ui;
import javax.swing.*; import java.awt.*; import java.net.URL;
public class SystemTrayEn { public static void main(String[] args) { JFrame frame = new JFrame(); frame.setBounds(500, 500, 200, 200); frame.setVisible(true); initSystemTray(frame); }
private static void initSystemTray(JFrame frame) { if (java.awt.SystemTray.isSupported()) {
URL resource = SystemTray.class.getResource("/工具_16.png"); assert resource != null; ImageIcon icon = new ImageIcon(resource); PopupMenu pop = new PopupMenu();
String str = "显示主窗体"; MenuItem displayJFrameItem = new MenuItem(str); displayJFrameItem.addActionListener(e -> frame.setVisible(true)); pop.add(displayJFrameItem);
String exitLabel = "退出"; MenuItem exitItem = new MenuItem(exitLabel); exitItem.addActionListener(e -> System.exit(0)); pop.add(exitItem);
TrayIcon tray = new TrayIcon(icon.getImage(), "CommandsUI", pop); java.awt.SystemTray systemTray = java.awt.SystemTray.getSystemTray(); try { systemTray.add(tray); } catch (AWTException e1) { e1.printStackTrace(); } } } }
|
运行效果
中文菜单会乱码,如下图所示:
讲上述代码的中文菜单注释掉,换成英文菜单,再次运行,可以看到英文菜单可以正常显示:
SystemTrayCH.java
G:\dev2\idea_workspace\MyJavaTools\RunableTools\src\demo\ui\SystemTrayCH.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| package demo.ui;
import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import java.net.URL;
public class SystemTrayCH {
public static void main(String[] args) throws FileNotFoundException { JFrame frame = new JFrame(); initSystemTrayUTF8(frame);
frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { frame.setVisible(false); } }); frame.setBounds(500, 500, 200, 200); frame.setVisible(true); }
private static void initSystemTrayUTF8(JFrame frame) { JDialog jDialog = new JDialog(); jDialog.setUndecorated(true); jDialog.setSize(1, 1);
JPopupMenu jPopupMenu = new JPopupMenu() { @Override public void firePopupMenuWillBecomeInvisible() { jDialog.setVisible(false); System.out.println("JPopupMenu不可见时绑定载体组件jDialog也不可见"); } }; jPopupMenu.setSize(100, 30);
JMenuItem exit = new JMenuItem("退出"); exit.addActionListener(e -> { System.out.println("点击了退出选项"); System.exit(0); }); JMenuItem showMainFrame = new JMenuItem("显示主窗体"); showMainFrame.addActionListener(e -> { System.out.println("显示主窗体"); frame.setVisible(true); });
jPopupMenu.add(showMainFrame); jPopupMenu.add(exit);
URL resource = SystemTrayCH.class.getResource("/工具_16.png"); Image image = Toolkit.getDefaultToolkit().createImage(resource); TrayIcon trayIcon = new TrayIcon(image); trayIcon.setImageAutoSize(true);
trayIcon.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { if (e.getButton() == 1) { frame.setVisible(true); } else if (e.getButton() == 3 && e.isPopupTrigger()) { jDialog.setLocation(e.getX() + 5, e.getY() - 5 - jPopupMenu.getHeight()); jDialog.setVisible(true); jPopupMenu.show(jDialog, 0, 0); } } }); systemTrayAdd(trayIcon); }
private static void systemTrayAdd(TrayIcon trayIcon) { SystemTray tray = SystemTray.getSystemTray(); try { tray.add(trayIcon); } catch (AWTException ex) { ex.printStackTrace(); } }
private static String getUTF8String(String str) { try { return new String(str.getBytes("UTF-8"), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } }
|
运行效果
参考资料
https://blog.csdn.net/TianYaZhongBieLi/article/details/102903765