如何为应用程序添加托盘图标
2010-04-24 22:18
169 查看
对于一些不是很需要与用户交互的应用程序来说,在应用程序最小化的时候将它变成托盘图标。对用户来说是一种不错的用户体验。那这个功能应该怎么样实现呢?其实实现功能十分的简单,我们只需要调用Shell_NotifyIcon函数就可以为应用程序添加托盘图标。然后我们只需要在提供一个回调函数处理相应的消息就可以了。
让我们来看一看Shell_NotifyIcon函数,该函数的完整声明如下:
参数dwMessage定义了该函数将要执行的功能。如我们传递NIM_ADD调用该函数,则函数执行后就可以为应用程序添加托盘图标。而我们传递NIM_DELETE调用该函数,则函数执行后就将删除应用程序的托盘图标。该参数还能接受的值还包括NIM_MODIFY、NIM_SETFOCUS、NIM_SETVERSION等,感兴趣的朋友可以参考MSDN来了解传递该值后函数将会执行的动作。
参数PNOTIFYICONDATA是一个指向NOTIFYICONDATA结构体的指针,我们可以通过填充该结构体来定制托盘图标中显示的图标和当鼠标停留在图标上显示的文字等。
下面让我们再来看看NOTIFYICONDATA结构体的主要成员如下:
成员cbSize表示该结构体的大小,我们只需要为该成员填入sizeof(NOTIFYICONDATA)就可以了。
成员hWnd表示要生成托盘的窗口句柄。
成员uID表示托盘图标的资源ID。
成员uFlags是一个掩码值,通过位域来判断结构体中哪些成员在Shell_NotifyIcon函数的调用中有效。我们一般为该成员覆的值为NIF_ICON | NIF_MESSAGE | NIF_TIP。该组合表示图标句柄、回调消息以及提示信息的相应成员变量有效。如果您还对其它的成员变量有兴趣,请参看MSDN。
成员uCallbackMessage表示一个用户自定义消息。
成员hIcon表示托盘图标的句柄。
成员szTip表示将鼠标放到托盘图标上时显示出来的提示文字。
下面在让我们来看一下添加、删除以及处理NotifyIcon消息的具体代码。
首先让我们来看一下添加托盘图标的代码。
然后再让我们来看一下删除托盘图标的代码。
下面再让我们来看一下在MFC下处理托盘图标消息的代码,比起上面的代码,要稍微麻烦了一点。不过也不是很难。
首先是在要添加托盘图标的窗口类中添加MFC的标准消息处理函数声明。
然后是在窗口类的实现文件中添加用户自定义消息和相应的消息映射。
然后就是实现OnNotifyIcon函数,在OnNotifyIcon函数中,wParam表示图标的资源ID,lParam表示消息ID,如lParam值可以是WM_LBUTTONDOWN、WM_RBUTTONDOWN等消息。
为了重用代码,也为了更方便的增加新的功能,我们完全可以将NotifyIcon做成一个类。而且在.Net下面,NotifyIcon本身就是一个封装好了的控件。我们的目标就是做一个与.Net下面NotifyIcon类似的类。隐藏添加、删除以及NotifyIcon消息处理的细节,而为用户提供跟.Net相似的事件订阅来处理NotifyIcon消息。隐藏NotifyIcon消息处理函数采用了宏定义的方法。具体代码如下:
如果有哪位朋友想要该类的测试代码的话,请在博客留言中留下自己的邮箱,我会将代码给您发送过来。
让我们来看一看Shell_NotifyIcon函数,该函数的完整声明如下:
BOOL Shell_NotifyIcon(__in DWORD dwMessage, __in PNOTIFYICONDATA lpdata)
参数dwMessage定义了该函数将要执行的功能。如我们传递NIM_ADD调用该函数,则函数执行后就可以为应用程序添加托盘图标。而我们传递NIM_DELETE调用该函数,则函数执行后就将删除应用程序的托盘图标。该参数还能接受的值还包括NIM_MODIFY、NIM_SETFOCUS、NIM_SETVERSION等,感兴趣的朋友可以参考MSDN来了解传递该值后函数将会执行的动作。
参数PNOTIFYICONDATA是一个指向NOTIFYICONDATA结构体的指针,我们可以通过填充该结构体来定制托盘图标中显示的图标和当鼠标停留在图标上显示的文字等。
下面让我们再来看看NOTIFYICONDATA结构体的主要成员如下:
typedef struct _NOTIFYICONDATA { DWORD cbSize; HWND hWnd; UINT uID; UINT uFlags; UINT uCallbackMessage; HICON hIcon; TCHAR szTip[128]; } NOTIFYICONDATA, *PNOTIFYICONDATA;
成员cbSize表示该结构体的大小,我们只需要为该成员填入sizeof(NOTIFYICONDATA)就可以了。
成员hWnd表示要生成托盘的窗口句柄。
成员uID表示托盘图标的资源ID。
成员uFlags是一个掩码值,通过位域来判断结构体中哪些成员在Shell_NotifyIcon函数的调用中有效。我们一般为该成员覆的值为NIF_ICON | NIF_MESSAGE | NIF_TIP。该组合表示图标句柄、回调消息以及提示信息的相应成员变量有效。如果您还对其它的成员变量有兴趣,请参看MSDN。
成员uCallbackMessage表示一个用户自定义消息。
成员hIcon表示托盘图标的句柄。
成员szTip表示将鼠标放到托盘图标上时显示出来的提示文字。
下面在让我们来看一下添加、删除以及处理NotifyIcon消息的具体代码。
首先让我们来看一下添加托盘图标的代码。
BOOL AddNotifyIcon(HWND hwndIcon, UINT uIcon, UINT uMsg, LPCTSTR pcszTips) { NOTIFYICONDATA nid; ZeroMemory(&nid, sizeof(NOTIFYICONDATA)); nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hwndIcon; nid.uID = uIcon; nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; nid.uCallbackMessage = uMsg; nid.hIcon = LoadIcon((HINSTANCE)GetWindowLong(hwndIcon, GWL_HINSTANCE), MAKEINTRESOURCE(uIcon)); lstrcpy(nid.szTip, pcszTips); return Shell_NotifyIcon(NIM_ADD, &nid); }
然后再让我们来看一下删除托盘图标的代码。
BOOL DelNotifyIcon(HWND hwndIcon, UINT uIcon) { NOTIFYICONDATA nid; ZeroMemory(&nid, sizeof(NOTIFYICONDATA)); nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hwndIcon; nid.uID = uIcon; return Shell_NotifyIcon(NIM_DELETE, &nid); }
下面再让我们来看一下在MFC下处理托盘图标消息的代码,比起上面的代码,要稍微麻烦了一点。不过也不是很难。
首先是在要添加托盘图标的窗口类中添加MFC的标准消息处理函数声明。
LRESULT OnNotifyIcon(WPARAM wParam, LPARAM lParam);
然后是在窗口类的实现文件中添加用户自定义消息和相应的消息映射。
#define WM_NOTIFY_ICON WM_USER + 0X7000 BEGIN_MESSAGE_MAP(CXXXDlg, CDialog) //... ON_MESSAGE(WM_NOTIFY_ICON, OnNotifyIcon) //... //}}AFX_MSG_MAP END_MESSAGE_MAP()
然后就是实现OnNotifyIcon函数,在OnNotifyIcon函数中,wParam表示图标的资源ID,lParam表示消息ID,如lParam值可以是WM_LBUTTONDOWN、WM_RBUTTONDOWN等消息。
LRESULT CxxxDlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam) { UINT uID = (UINT)wParam; UINT uMsg = (UINT)lParam; switch(uMsg) { case WM_LBUTTONDOWN: //do something here break; case WM_LBUTTONDBLCLK: //do something here break; case WM_RBUTTONDOWN: //do something here break; case WM_MOUSEMOVE: //do something here break; default: break; } return 0; }
为了重用代码,也为了更方便的增加新的功能,我们完全可以将NotifyIcon做成一个类。而且在.Net下面,NotifyIcon本身就是一个封装好了的控件。我们的目标就是做一个与.Net下面NotifyIcon类似的类。隐藏添加、删除以及NotifyIcon消息处理的细节,而为用户提供跟.Net相似的事件订阅来处理NotifyIcon消息。隐藏NotifyIcon消息处理函数采用了宏定义的方法。具体代码如下:
#ifndef __NOTIFY__ICON__H #define __NOTIFY__ICON__H #include <Windows.h> //////////////////////////////////////////////////////////////////////////////////////////////////// /// /enum NotifyIconEventType /// /// /brief NotifyIcon注册的事件类型.包括鼠标左键单击、鼠标左键双击、 /// 鼠标右键单击以及鼠标移动 //////////////////////////////////////////////////////////////////////////////////////////////////// enum NotifyIconEventType { NOTIFY_ICON_LBUTTON_CLICK, NOTIFY_ICON_LBUTTON_DCLICK, NOTIFY_ICON_RBUTTON_CLICK, NOTIFY_ICON_MOUSE_MOVE }; //////////////////////////////////////////////////////////////////////////////////////////////////// /// /typedef void (CALLBACK *NotifyIconLButtonClickEventHandle) (UINT) /// /// /brief 鼠标左键单击事件处理回调函数 //////////////////////////////////////////////////////////////////////////////////////////////////// typedef void (CALLBACK *NotifyIconLButtonClickEventHandle) (UINT); //////////////////////////////////////////////////////////////////////////////////////////////////// /// /typedef void (CALLBACK *NotifyIconLButtonDClickEventHandle)(UINT) /// /// /brief 鼠标左键双击事件处理回调函数 //////////////////////////////////////////////////////////////////////////////////////////////////// typedef void (CALLBACK *NotifyIconLButtonDClickEventHandle)(UINT); //////////////////////////////////////////////////////////////////////////////////////////////////// /// /typedef void (CALLBACK *NotifyIconRButtonClickEventHandle) (UINT) /// /// /brief 鼠标右键单击事件处理回调函数 //////////////////////////////////////////////////////////////////////////////////////////////////// typedef void (CALLBACK *NotifyIconRButtonClickEventHandle) (UINT); //////////////////////////////////////////////////////////////////////////////////////////////////// /// /typedef void (CALLBACK *NotifyIconMouseMoveEventHandle) (UINT) /// /// /brief 鼠标移动事件处理回调函数 //////////////////////////////////////////////////////////////////////////////////////////////////// typedef void (CALLBACK *NotifyIconMouseMoveEventHandle) (UINT); #define WM_NOTIFY_ICON WM_USER + 0X7000 #define ON_NOTIFY_ICON_FUNC LRESULT OnNotifyIcon(WPARAM wParam, LPARAM lParam); #define ON_NOTIFY_ICON OnNotifyIcon #define HANDLE_EVENT(NotifyIconEvent, uID) if (NULL != NotifyIconEvent){NotifyIconEvent(uID);} //////////////////////////////////////////////////////////////////////////////////////////////////// /// /def ON_NOTIFY_ICON_MESSAGE(xxxDlg) LRESULT xxxDlg::OnNotifyIcon(WPARAM wParam, LPARAM /// lParam) /// /// /brief 执行NotifyIcon的消息循环.包括处理鼠标左键单击、鼠标左键双击、 /// 鼠标右键单击以及鼠标移动. /// /// /remarks Shining100, 2010-04-24. /// /// /param xxxDlg 应用程序主窗口类. //////////////////////////////////////////////////////////////////////////////////////////////////// #define ON_NOTIFY_ICON_MESSAGE(CXXXDlg) LRESULT CXXXDlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam) / { / UINT uID = (UINT)wParam;/ UINT uMsg = (UINT)lParam;/ / NotifyIconLButtonClickEventHandle NotifyIconLButtonClick = / (NotifyIconLButtonClickEventHandle)CNotifyIcon::GetEventHandle(NOTIFY_ICON_LBUTTON_CLICK);/ NotifyIconLButtonDClickEventHandle NotifyIconLButtonDClick = / (NotifyIconLButtonDClickEventHandle)CNotifyIcon::GetEventHandle(NOTIFY_ICON_LBUTTON_DCLICK);/ NotifyIconRButtonClickEventHandle NotifyIconRButtonClick = / (NotifyIconRButtonClickEventHandle)CNotifyIcon::GetEventHandle(NOTIFY_ICON_RBUTTON_CLICK);/ NotifyIconMouseMoveEventHandle NotifyIconMouseMove = / (NotifyIconMouseMoveEventHandle)CNotifyIcon::GetEventHandle(NOTIFY_ICON_MOUSE_MOVE);/ / switch(uMsg)/ {/ case WM_LBUTTONDOWN:/ HANDLE_EVENT(NotifyIconLButtonClick, uID)/ break;/ case WM_LBUTTONDBLCLK:/ HANDLE_EVENT(NotifyIconLButtonDClick, uID)/ break;/ case WM_RBUTTONDOWN:/ HANDLE_EVENT(NotifyIconRButtonClick, uID)/ break;/ case WM_MOUSEMOVE:/ HANDLE_EVENT(NotifyIconMouseMove, uID)/ break;/ default:/ break;/ }/ / return 0;/ } //////////////////////////////////////////////////////////////////////////////////////////////////// /// /class CNotifyIcon /// /// /brief 窗口托盘图标. /// 使用方法: 1.将宏ON_NOTIFY_ICON_FUNC放在窗口类定义中. /// 2.在窗口类实现文件中添加消息映射. /// ON_MESSAGE(WM_NOTIFY_ICON, ON_NOTIFY_ICON) /// 3.在窗口类构造函数中利用CNotifyIcon::AddEventHandle /// 添加事件处理函数. /// 4.将宏ON_NOTIFY_ICON_MESSAGE(CXXXDlg)放到窗口类的实现中 /// CXXXDlg为你的窗口类的名称. /// 5.编写自己的消息处理函数. /// /// /author Shining100 /// /date 2010-4-23 //////////////////////////////////////////////////////////////////////////////////////////////////// class CNotifyIcon { public: CNotifyIcon(void); ~CNotifyIcon(void); public: //////////////////////////////////////////////////////////////////////////////////////////////////// /// /fn bool AddNotifyIcon(HWND hwndIcon, UINT uIcon, UINT iMsg, LPCTSTR pszTips) /// /// /brief 创建窗口托盘图标. /// /// /author Shining100 /// /date 2010-4-23 /// /// /param hwndIcon 创建托盘图标窗口的句柄. /// /param uIcon 在托盘处显示的图标资源ID. /// /param uMsg 托盘图标订阅的消息. /// /param pszTips 托盘图标显示的信息. /// /// /return 成功返回TRUE, 失败返回FALSE. //////////////////////////////////////////////////////////////////////////////////////////////////// BOOL AddNotifyIcon(HWND hwndIcon, UINT uIcon, UINT uMsg, LPCTSTR pcszTips); //////////////////////////////////////////////////////////////////////////////////////////////////// /// /fn bool DelNotifyIcon(HWND hwndIcon, UINT uIcon) /// /// /brief 删除窗口托盘图标. /// /// /author Shining100 /// /date 2010-4-23 /// /// /param hwndIcon 删除托盘图标窗口的句柄. /// /param uIcon 在托盘处显示的图标资源 ID. /// /// /return 成功返回TRUE, 失败返回FALSE. //////////////////////////////////////////////////////////////////////////////////////////////////// BOOL DelNotifyIcon(HWND hwndIcon, UINT uIcon); //////////////////////////////////////////////////////////////////////////////////////////////////// /// /fn virtual bool PopMenu(UINT uMenu) /// /// /brief 弹出托盘菜单. /// /// /author Shining100 /// /date 2010-4-23 /// /// /param hwndIcon 托盘图标窗口的句柄. /// /param uMenu 菜单的资源ID. /// /// /return 成功返回TRUE, 失败返回FALSE. /// /// /remarks 该函数只能简单的弹出指定的菜单,如果需要在弹出菜单时禁用某些 /// 菜单项,请重载该函数. //////////////////////////////////////////////////////////////////////////////////////////////////// virtual BOOL PopMenu(HWND hwndIcon, UINT uMenu); protected: static void ProcessEventHandle(NotifyIconEventType niet, LPVOID func); public: //////////////////////////////////////////////////////////////////////////////////////////////////// /// /fn static void AddEventHandle(NotifyIconEventType niet, LPVOID func) /// /// /brief 注册NotifyIcon事件.包括鼠标左键单击、鼠标左键双击、 /// 鼠标右键单击以及鼠标移动等事件. /// /// /author Shining100 /// /date 2010-04-24 /// /// /param niet 事件类型. /// /param func 事件处理函数. //////////////////////////////////////////////////////////////////////////////////////////////////// static void AddEventHandle(NotifyIconEventType niet, LPVOID func); //////////////////////////////////////////////////////////////////////////////////////////////////// /// /fn static void DelEventHandle(NotifyIconEventType niet) /// /// /brief 注销NotifyIcon事件.包括鼠标左键单击、鼠标左键双击、 /// 鼠标右键单击以及鼠标移动等事件. /// /// /author Shining100 /// /date 2010-04-24 /// /// /param niet 事件类型. //////////////////////////////////////////////////////////////////////////////////////////////////// static void DelEventHandle(NotifyIconEventType niet); //////////////////////////////////////////////////////////////////////////////////////////////////// /// /fn static LPVOID GetEventHandle(NotifyIconEventType niet) /// /// /brief 获取NotifyIcon事件.包括鼠标左键单击、鼠标左键双击、 /// 鼠标右键单击以及鼠标移动等事件. /// /// /author Shining100 /// /date 2010-04-24 /// /// /param niet 事件类型. /// /// /return 事件处理函数. //////////////////////////////////////////////////////////////////////////////////////////////////// static LPVOID GetEventHandle(NotifyIconEventType niet); protected: static NotifyIconLButtonClickEventHandle m_NotifyIconLButtonClick; static NotifyIconLButtonDClickEventHandle m_NotifyIconLButtonDClick; static NotifyIconRButtonClickEventHandle m_NotifyIconRButtonClick; static NotifyIconMouseMoveEventHandle m_NotifyIconMouseMove; }; #endif
#include "StdAfx.h" // 如果工程中不需要预编译,请删除掉该头文件声明 #include "NotifyIcon.h" NotifyIconLButtonClickEventHandle CNotifyIcon::m_NotifyIconLButtonClick = NULL; NotifyIconLButtonDClickEventHandle CNotifyIcon::m_NotifyIconLButtonDClick = NULL; NotifyIconRButtonClickEventHandle CNotifyIcon::m_NotifyIconRButtonClick = NULL; NotifyIconMouseMoveEventHandle CNotifyIcon::m_NotifyIconMouseMove = NULL; CNotifyIcon::CNotifyIcon(void) { } CNotifyIcon::~CNotifyIcon(void) { } BOOL CNotifyIcon::AddNotifyIcon(HWND hwndIcon, UINT uIcon, UINT uMsg, LPCTSTR pcszTips) { NOTIFYICONDATA nid; ZeroMemory(&nid, sizeof(NOTIFYICONDATA)); nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hwndIcon; nid.uID = uIcon; nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; nid.uCallbackMessage = uMsg; nid.hIcon = LoadIcon((HINSTANCE)GetWindowLong(hwndIcon, GWL_HINSTANCE), MAKEINTRESOURCE(uIcon)); lstrcpy(nid.szTip, pcszTips); return Shell_NotifyIcon(NIM_ADD, &nid); } BOOL CNotifyIcon::DelNotifyIcon(HWND hwndIcon, UINT uIcon) { NOTIFYICONDATA nid; ZeroMemory(&nid, sizeof(NOTIFYICONDATA)); nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hwndIcon; nid.uID = uIcon; return Shell_NotifyIcon(NIM_DELETE, &nid); } BOOL CNotifyIcon::PopMenu(HWND hwndIcon, UINT uMenu) { POINT ptCur; ::GetCursorPos(&ptCur); HMENU menu; menu = LoadMenu((HINSTANCE)GetWindowLong(hwndIcon, GWL_HINSTANCE), MAKEINTRESOURCE(uMenu)); menu = GetSubMenu(menu, 0); SetForegroundWindow(hwndIcon); // 点击非弹出菜单区域后,使菜单消失 return TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, ptCur.x, ptCur.y, 0, hwndIcon, NULL); } void CNotifyIcon::ProcessEventHandle(NotifyIconEventType niet, LPVOID func) { switch(niet) { case NOTIFY_ICON_LBUTTON_CLICK: m_NotifyIconLButtonClick = (NotifyIconLButtonClickEventHandle)func; break; case NOTIFY_ICON_LBUTTON_DCLICK: m_NotifyIconLButtonDClick = (NotifyIconLButtonDClickEventHandle)func; break; case NOTIFY_ICON_RBUTTON_CLICK: m_NotifyIconRButtonClick = (NotifyIconRButtonClickEventHandle)func; break; case NOTIFY_ICON_MOUSE_MOVE: m_NotifyIconMouseMove = (NotifyIconMouseMoveEventHandle)func; break; default: break; } } void CNotifyIcon::AddEventHandle(NotifyIconEventType niet, LPVOID func) { ProcessEventHandle(niet, func); } void CNotifyIcon::DelEventHandle(NotifyIconEventType niet) { ProcessEventHandle(niet, NULL); } LPVOID CNotifyIcon::GetEventHandle(NotifyIconEventType niet) { switch(niet) { case NOTIFY_ICON_LBUTTON_CLICK: return (LPVOID)m_NotifyIconLButtonClick; case NOTIFY_ICON_LBUTTON_DCLICK: return (LPVOID)m_NotifyIconLButtonDClick; case NOTIFY_ICON_RBUTTON_CLICK: return (LPVOID)m_NotifyIconRButtonClick; case NOTIFY_ICON_MOUSE_MOVE: return (LPVOID)m_NotifyIconMouseMove; default: break; } return NULL; }
如果有哪位朋友想要该类的测试代码的话,请在博客留言中留下自己的邮箱,我会将代码给您发送过来。
相关文章推荐
- 为应用程序添加托盘图标的一种方法
- win10系统如何在桌面上添加应用程序图标
- 如何在任务栏添加托盘图标
- iOS如何添加图片资源以及设置应用程序图标
- BCB如何将应用程序图标写到系统托盘中
- fedora 17 如何把应用程序的图标添加到桌面上
- 如何给V-Play应用程序添加图标?
- 为自己的应用程序添加系统托盘图标
- VB6如何在托盘中写入应用程序图标
- fedora 17 如何把应用程序的图标添加到桌面上
- fedora 17如何把应用程序的图标添加到桌面上
- 如何给Win32智能设备控制台应用程序添加图标
- win10系统如何在桌面上添加应用程序图标
- Linux如何把应用程序图标添加到桌面上
- 如何在系统托盘(panel)中显示应用程序图标和气球帮助信息(balloon tooltips)
- Qt中如何添加ICON图标 Qt设置应用程序图标
- qt 如何为应用程序添加图标!
- iOS如何添加图片资源以及设置应用程序图标
- 如何把程序图标添加到系统托盘上
- Ubuntu下经典JAVA开发环境搭建 以及 Ubuntu中如何在桌面、启动面板以及应用程序菜单上添加图标