实现的关键是调用Windows Shell 的API Shell_NotifyIcon,该函数有两个参数,第一个参数指名操作类型,第二个参数是一个NOTIFYICONDATA结构,保存了操作相关的信息,比如图标,工具提示文本等等。关于该函数的详细情况可以在MSDN上查阅得知,这里不多叙述。
下面贴出类的实现代码,后面会有使用方法的介绍(这个Blog居然没有C++的Language Filter,太不爽了,暂时用Java的),
头文件
#define __CSYSTEMTRAY_H
#include " shellapi.h "
#define WM_TRAY_MSG WM_USER + 0x01 // 自定义消息,用以接收来自托盘的反馈
class CSystemTray
... {
public:
CSystemTray(void);
public:
~CSystemTray(void);
void Destroy();
BOOL Create(HWND hParent, HICON hIcon, LPCTSTR szToolTip); //hParent 是接收WM_TRAY_MSG消息的窗口
BOOL ModifyIcon(HICON hIcon);
BOOL ModifyToolTipText(LPCTSTR szToolTip);
BOOL ModifyBalloonText(LPCTSTR szTitle, LPCTSTR szInfo);
BOOL ModifyBalloonIcon(HICON hIcon);
BOOL SetFocus();
//BOOL AnimateIcon(HICON *pIconArray, UINT nSize, DWORD dwTimeInter);
private:
void Wait(int nSeconds);
HWND m_hParent;
HICON m_hIconTray, m_hIconBalloon;
NOTIFYICONDATA m_nidSystemTray;
} ;
#endif
实现:
CSystemTray::CSystemTray( void ):m_hParent(NULL), m_hIconTray(NULL), m_hIconBalloon(NULL)
... {
::ZeroMemory(&m_nidSystemTray, sizeof(NOTIFYICONDATA));
}
CSystemTray:: ~ CSystemTray( void )
... {
Destroy();
}
BOOL CSystemTray::Create(HWND hParent, HICON hIcon, LPCTSTR szToolTip)
... {
m_hParent = hParent;
m_nidSystemTray.cbSize = sizeof(NOTIFYICONDATA);
m_nidSystemTray.hWnd = m_hParent;
m_nidSystemTray.hIcon = m_hIconTray = hIcon;
m_nidSystemTray.uFlags = NIF_ICON | NIF_MESSAGE;
m_nidSystemTray.uCallbackMessage = WM_TRAY_MSG;
if (szToolTip)
...{
m_nidSystemTray.uFlags |= NIF_TIP;
_tcscpy(m_nidSystemTray.szTip, szToolTip);
}
return Shell_NotifyIcon(NIM_ADD, &m_nidSystemTray);
}
BOOL CSystemTray::ModifyIcon(HICON hIcon)
... {
ASSERT(m_nidSystemTray.hWnd != NULL);
m_nidSystemTray.hIcon = hIcon;
m_nidSystemTray.uFlags = NIF_ICON;
return Shell_NotifyIcon(NIM_MODIFY, &m_nidSystemTray);
}
BOOL CSystemTray::ModifyToolTipText(LPCTSTR szToolTip)
... {
ASSERT(m_nidSystemTray.hWnd != NULL);
_tcscpy(m_nidSystemTray.szTip, szToolTip);
m_nidSystemTray.uFlags = NIF_TIP;
return Shell_NotifyIcon(NIM_MODIFY, &m_nidSystemTray);
}
BOOL CSystemTray::ModifyBalloonText(LPCTSTR szTitle, LPCTSTR szInfo)
... {
ASSERT(m_nidSystemTray.hWnd != NULL);
_tcscpy(m_nidSystemTray.szInfoTitle, szTitle);
_tcscpy(m_nidSystemTray.szInfo, szInfo);
m_nidSystemTray.hIcon = m_hIconBalloon;
m_nidSystemTray.uFlags = NIF_INFO | NIF_ICON;
BOOL bRet = Shell_NotifyIcon(NIM_MODIFY, &m_nidSystemTray);
if (bRet)
...{
m_nidSystemTray.hIcon = m_hIconTray;
m_nidSystemTray.uFlags = NIF_ICON;
return Shell_NotifyIcon(NIM_MODIFY, &m_nidSystemTray);
}
else return FALSE;
}
BOOL CSystemTray::ModifyBalloonIcon(HICON hIcon)
... {
m_nidSystemTray.dwInfoFlags = NIIF_USER;
m_nidSystemTray.hIcon = m_hIconBalloon = hIcon;
m_nidSystemTray.uFlags = NIF_INFO | NIF_ICON;
BOOL bRet = FALSE;
bRet = Shell_NotifyIcon(NIM_MODIFY, &m_nidSystemTray);
if (bRet)
...{
m_nidSystemTray.hIcon =m_hIconTray;
m_nidSystemTray.uFlags = NIF_ICON;
return Shell_NotifyIcon(NIM_MODIFY, &m_nidSystemTray);
}
else return FALSE;
}
BOOL CSystemTray::SetFocus()
... {
ASSERT(m_nidSystemTray.hWnd != NULL);
return Shell_NotifyIcon(NIM_SETFOCUS, &m_nidSystemTray);
}
void CSystemTray::Destroy()
... {
if(m_nidSystemTray.hWnd != NULL)
...{
Shell_NotifyIcon(NIM_DELETE, &m_nidSystemTray);
::ZeroMemory(&m_nidSystemTray, sizeof(NOTIFYICONDATA));
}
m_hParent = NULL;
}
首先创建一个对话框程序,将上述文件添加至工程。
在xxxDlg.h(xxx是你的工程名)文件中,添加#include "systemtray.h",在类声明中定一个CSystemTray类型变量,比如m_stMyProg;
然后再对话框的实现文件OnInitDialog函数中添加以下代码
m_stMyProg.Create(m_hWnd,::LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ACCEPT)), _T("This is a SystemTray example"));
其中IDI_ACCEPT是一个事先定义好的图标资源。
这样启动程序以后,我们就可以在托盘上看到相应的图标了
接下来在程序的任何位置调用ModifyIcon可以修改托盘的图标,调用ModifyToolTip可以修改托盘的工具提示(tooltip),调用ModifyBalloonIcon可以修改气球提示的图标,相应的,如果想调用系统默认图标可以调用函数::LoadStandardIcon。需要注意的是,气球提示只有在每次修改文本时才会出现,因此如果想立即看到修改图标的效果,请调用一次ModifyBalloonText。OK!
前面的头文件中定义了一个WM_TRAY_MSG消息,当鼠标经过托盘图标时该消息就会得到响应,其中消息相关的lParam参数表示鼠标的操作,比如在托盘处单击了一下鼠标左键,lParam就是一个WM_LBUTTONDOWN消息,可以根据此消息来创建上下文菜单,等等。
首先要在对话框的头文件中添加一个消息相应函数的声明
afx_msg LRESULT OnTrayMsg(WPARAM wParam, LPARAM lParam);
再在MFC的消息映射中添加 ON_MESSAGE(WM_TRAY_MSG, OnTrayMsg)
最后在对话框的实现文件中添加对该函数的实现
... {
switch (lParam)
...{
case WM_LBUTTONDOWN:
//do someting...
break;
case WM_RBUTTONDOWN:
//then do another...
...
default:
break;
}
return 0;
}
根据接收到的不同鼠标消息对其进行响应。
这个类写的还不够完整,以后会添加关于托盘鼠标动画的支持,等等。目前先到这里
2007.10.9 by 赵科进(GodBird)