我们有些程序会想要托盘处显示图标,最小化到系统栏;关闭按钮不关闭程序,也是最小化到系统栏;点击托盘图标激活窗口,通过托盘图标的弹出菜单来退出程序。
本段代码就是要完成这样的功能,是 SWT 来实现的。
直接代码给出,代码中有较详细的注释,说明了本程序的功能及实现。文中的任务栏和系统栏应该知道是指哪一段吧,微软就是这么定义的,用 spyxx 的 findwindow 窥探一下就知道了。
1 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 |
package com.unmi; import org.eclipse.swt.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.*; /** * SWT 3.0 开始引入了 Tray,可以在系统栏放置你的程序图标了 * 本程序实现的功能有四: * 1. 点击窗口的最小化或关闭按钮都是隐藏窗口--任务栏里不显示,不退出程序 * 2. 窗口隐藏时,任务栏无图标,系统栏有图标;窗口处于显示状态时则恰好相反 * 3. 窗口隐藏时可通过单击系统栏图标或点击系统栏的 "显示窗口" 菜单显示窗口 * 4. 程序只能通过点击系统栏的 "退出程序" 菜单项退出,窗口的 X 按钮无效 * @author Unmi * */ public class TrayExample { public static void main(String[] args) { Display display = new Display(); //禁用掉了最大化按钮 final Shell shell = new Shell(display,SWT.SHELL_TRIM ^ SWT.MAX); shell.setText("TrayExample"); //取系统中预置的图标,省得测试运行时还得加个图标文件 shell.setImage(display.getSystemImage(SWT.ICON_WORKING)); //构造系统栏控件 final Tray tray = display.getSystemTray(); final TrayItem trayItem = new TrayItem(tray, SWT.NONE); //程序启动时,窗口是显示的,所以系统栏图标隐藏 trayItem.setVisible(false); trayItem.setToolTipText(shell.getText()); trayItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { toggleDisplay(shell, tray); } }); final Menu trayMenu = new Menu(shell, SWT.POP_UP); MenuItem showMenuItem = new MenuItem(trayMenu, SWT.PUSH); showMenuItem.setText("显示窗口(&s)"); //显示窗口,并隐藏系统栏中的图标 showMenuItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { toggleDisplay(shell, tray); } }); trayMenu.setDefaultItem(showMenuItem); new MenuItem(trayMenu, SWT.SEPARATOR); //系统栏中的退出菜单,程序只能通过这个菜单退出 MenuItem exitMenuItem = new MenuItem(trayMenu, SWT.PUSH); exitMenuItem.setText("退出程序(&x)"); exitMenuItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { shell.dispose(); } }); //在系统栏图标点击鼠标右键时的事件,弹出系统栏菜单 trayItem.addMenuDetectListener(new MenuDetectListener(){ public void menuDetected(MenuDetectEvent e) { trayMenu.setVisible(true); } }); trayItem.setImage(shell.getImage()); //注册窗口事件监听器 shell.addShellListener(new ShellAdapter() { //点击窗口最小化按钮时,窗口隐藏,系统栏显示图标 public void shellIconified(ShellEvent e) { toggleDisplay(shell, tray); } //点击窗口关闭按钮时,并不终止程序,而时隐藏窗口,同时系统栏显示图标 public void shellClosed(ShellEvent e) { e.doit = false; //消耗掉原本系统来处理的事件 toggleDisplay(shell, tray); } }); shell.setSize(320, 240); center(shell); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } /** * 窗口是可见状态时,则隐藏窗口,同时把系统栏中图标删除 * 窗口是隐藏状态时,则显示窗口,并且在系统栏中显示图标 * @param shell 窗口 * @param tray 系统栏图标控件 */ private static void toggleDisplay(Shell shell, Tray tray) { try { shell.setVisible(!shell.isVisible()); tray.getItem(0).setVisible(!shell.isVisible()); if (shell.getVisible()) { shell.setMinimized(false); shell.setActive(); } } catch (Exception e) { e.printStackTrace(); } } /** * 窗口居中显示 * @param shell 要显示的窗口 */ private static void center(Shell shell){ Monitor monitor = shell.getMonitor(); Rectangle bounds = monitor.getBounds (); Rectangle rect = shell.getBounds (); int x = bounds.x + (bounds.width - rect.width) / 2; int y = bounds.y + (bounds.height - rect.height) / 2; shell.setLocation (x, y); } } |
实现效果如下:
左图是窗口显示时,系统栏中无图标,而任务栏中有图标。右图是窗口隐藏时,只有系统栏有图标。
过后,看了翻译软件 LINGOES 灵格斯的表现形式是:
1. 任何时候系统栏都有图标
2. 最小化按钮不会隐藏窗口,只是最小化到任务栏
3. 关闭按钮也是不会关闭程序,而是最小化到系统栏
4. 也是只能通过托盘图标的弹出菜单项“退出” 来关闭程序
参考:http://www.eclipseworld.org/bbs/read-cec-tid-15458-fpage-9.html
但最后还留有一个问题:如何实现窗口可见状态时,任务栏里什么都不显示呢?
本文链接 https://yanbin.blog/swt-systray-close-via-tray/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
你写的窗口如果是继承自JDialog的话,则任务栏什么也不会显示
# while (!shell.isDisposed()) {
# if (!display.readAndDispatch())
# display.sleep();
# }
怎么像MFC的事件循环哦,
唉,SWT就是和SWING没法比了
SWT的程序如果继承自 JDialog 就不伦不类了,也没这么试过,用SWT一般也不建议这么做,虽然SWT也提供了 SWT-AWT 相应类
SWT 确实很多东西太像 MFC 的,比如
窗口构造方式:
final Shell shell = new Shell(display,SWT.SHELL_TRIM ^ SWT.MAX);
SWT中很多变量在MFC都有相应的全局常量对应
资源的获取方式:
display.getSystemImage(SWT.ICON_WORKING
不过SWT可还是比MFC简单多了。
博主的代码很工整,尊重知识产权。
请教,如何实现启动时不显示shell窗口,只显示托盘图标;可以通过托盘图标显示shell窗口?
启动 java window 程序时用命令
start javaw ...........
就不会出现 shell 窗口,不要用 java,就这么简单。
晕,我把意思表述错误了。
不是那个控制台窗口,是SWT中的shell。shell.open()以后会显示shell窗口,我想问的是如何实现程序启动时隐藏主窗口,而只显示托盘?
我在shell.open()后加了一句shell.setVisiable(false),但启动时窗口会一闪而过,不完美,请问有办法吗?
多谢回复!!!
启动程序时不要执行
shell.open();
设置托盘图标启动时可见
trayItem.setVisible(true);
试一试看看效果。
可以了!多谢!!
刚开始学SWT,许多东西不懂,没想到这样做。
楼主,你太强了
我正要这个,谢了哦
楼主,我想问一下,如果程序主页面用得是jfc的applicationwindow,如何设置系统托盘?我尝试引用您的代码,可是报错,shell不能引用。
这是用的 SWT 组件的做法,不适用于 jfc
如果是 jdk1.6的 jfc 可以用 SystemTray,具体用法可参考
java实现系统托盘
http://www.blogjava.net/kissjava/archive/2008/07/30/218654.html
谢谢楼主的解答。
看得出博主在这个blog中花费了很多心思的。