您的位置:首页 > 其它

如何为应用程序添加托盘图标

2010-04-24 22:18 169 查看
对于一些不是很需要与用户交互的应用程序来说,在应用程序最小化的时候将它变成托盘图标。对用户来说是一种不错的用户体验。那这个功能应该怎么样实现呢?其实实现功能十分的简单,我们只需要调用Shell_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;
}


如果有哪位朋友想要该类的测试代码的话,请在博客留言中留下自己的邮箱,我会将代码给您发送过来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: