WINDOWS系统托盘是一个特殊区域,通常在桌面的右下角,也就是任务栏的右边。系统常驻在托盘的程序有时钟,音量控制,输入法,网络状态等。第三方应用如QQ程序也是一个典型的托盘程序,当最小化时企鹅会乖乖的待在屏幕右下角等待主人的呼唤。
系统托盘的方便之处在于,程序在暂时不用时,将它放到托盘里,随用随叫,不必将其关闭。而QQ在接收到消息后,也会在托盘中闪动提示,十分人性化。
那么如何用VC++来开发托盘程序呢?下面会用一个例子来玩转WINDOWS托盘程序。
首先,定义一下需要的功能。(需求确定)
-
程序最小化到托盘。
-
右键点击,显示一个菜单。
-
鼠标左键双击托盘图标,打开程序。
-
程序中点击一个按钮,改变托盘图标。
好了,就这么简单的Demo,下面看看如何实现。
其次,归纳一下用到的技术点。
-
托盘相关API
-
MFC对鼠标操作消息的接收
先来说说托盘相关的API。MFC并没有直接提高便利的类来支持系统托盘编程,我们需要用到SHELLAPI中的Shell_NotifyIcon函数。原型为:
BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA lpdata );
函数很简单清晰,只有两个参数。参数一dwMessage用来指定托盘的动作,这是一个四字节的值。如下:
-
NIM_ADD(0X00000000):添加一个系统托盘
-
NIM_MODIFY(0X00000001):系统托盘的修改
-
NIM_DELETE(0X00000002):系统托盘的删除
-
NIM_SETFOCUS(0X00000003):令系统托盘获得焦点
-
NIM_SETVERSION(0X00000004):系统托盘设置版本
参数二PNOTIFYICONDATA是专门为此服务的结构体。原型如下:
typedef struct _NOTIFYICONDATA { DWORD cbSize;//结构体的大小,单位是字节 HWND hWnd;//此托盘程序的句柄 UINT uID;// 系统为托盘区域每个图标分配的ID UINT uFlags;//简单的说,就是一个标示 UINT uCallbackMessage;//回调消息。需要自定义一个消息,用来接收鼠标滑过或点击等消息。 HICON hIcon;//图标 TCHAR szTip[64];//提示文字的大小 DWORD dwState;//图标的状态 DWORD dwStateMask;//与上面类似 TCHAR szInfo[256];//显示在气泡通知中的文本 union { UINT uTimeout; UINT uVersion; }; TCHAR szInfoTitle[64];//气泡通知的标题 DWORD dwInfoFlags;//修改气泡通知相关的标示 GUID guidItem;//图标的GUID HICON hBalloonIcon;//气泡通知的图标 } NOTIFYICONDATA, *PNOTIFYICONDATA;
再来说说MFC中对鼠标操作信息的接收。
其实上面的调查结果一出,这个问题也就迎刃而解了。关键在uCallbackMessage。我们会自定义一个消息,比如就叫做WM_ICON_NOTIFY,当此托盘图标有鼠标滑过,悬停或点击,键盘操作时回调这个接收自定义消息的函数来处理。这一切都被安排好了,我们照着做就可以了。
第三、功能的实现
1.最小化到托盘
创建托盘的函数ToTray:
m_tnd.cbSize = sizeof(NOTIFYICONDATA); m_tnd.hWnd = pWnd->GetSafeHwnd(); m_tnd.uID = uID; m_tnd.hIcon = icon; m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; m_tnd.uCallbackMessage = uCallbackMessage; strcpy (m_tnd.szTip, szToolTip); // Set the tray icon Shell_NotifyIcon(NIM_ADD, &m_tnd);
窗口最小化在OnSysCommand中判断:
else if (nID == SC_MINIMIZE) { ToTray(); ShowWindow(SW_HIDE);//隐藏窗口 }
2、3功能都可以在获得托盘事件函数处理:
LRESULT CTrayIcon::OnTrayNotification(UINT wParam, LONG lParam) { //Return quickly if its not for this tray icon if (wParam != m_tnd.uID) return 0L; // Clicking with right or left button brings up a context menu if (LOWORD(lParam) == WM_RBUTTONUP /*|| LOWORD(lParam) == WM_LBUTTONUP*/) { //TODO:WHEN RIGHT CLICK,YOUR MENU SHOW HERE } else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) { //TODO:DOUBLE LEFT CLICK,SHOW MAIN WINDOW } return 1; }
4.修改图标
这个就比较容易了,直接修改参数即可:
m_tnd.uFlags = NIF_ICON; m_tnd.hIcon = hIcon; Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
完整的例子请下载demo代码,借用了网上比较流行的封装好的TrayIcon类。
参考:
MSDN上的详细解释:http://msdn.microsoft.com/en-us/library/bb762159(VS.85).aspx
Vckbase:http://www.vckbase.com/index.php/cv/122