在系统桌面右下角的托盘区域,创建一个托盘图标,已经是很多软件的标配了,特别是IM即时通讯软件,要在托盘图标上显示来消息时的闪动头像。
其实托盘图标创建很简单,使用起来也比较方便,主要是调用Shell_NotifyIcon API函数,传入不同参数表示对应的操作:
1)NIM_ADD:创建一个托盘图标;
2)NIM_MODIFY:修改托盘图标,主要是用来修改图标和提示文字的;
3)NIM_DELETE:删除托盘图标。
下面给出一个完整的托盘图标封装类。
主要有CTrayIcon::Create、CTrayIcon::SetIcon、CTrayIcon::SetTooltipText、CTrayIcon::OnIconNotification等几个接口。其中,CTrayIcon::Create接口用来创建托盘图标;CTrayIcon::SetIcon用来设置图标或者修改图标;CTrayIcon::SetTooltipText用来设置托盘图标的提示文字;CTrayIcon::OnIconNotification用来处理托盘图标的鼠标消息。
CTrayIcon类的头文件如下:
#ifndef TRAYICON_H
#define TRAYICON_H
class CTrayIcon
{
private:
CTrayIcon();
CTrayIcon( CWnd* pWnd, WORD uCallbackMessage, LPCTSTR szTip, HICON icon, WORD uID );
public:
~CTrayIcon();
static CTrayIcon& Instance();
public:
// 创建系统图标
BOOL Create( CWnd* pWnd, WORD uCallbackMessage, LPCTSTR szTip, HICON icon, WORD uID );
// 获取NOTIFYICONDATA信息
NOTIFYICONDATA GetNotifyIconData(){ return m_tnd; }
// 关于提示文本
BOOL32 SetTooltipText( LPCTSTR pszTooltipText );
BOOL32 SetTooltipText( WORD nID );
CString GetTooltipText() const;
// 关于图标
BOOL32 SetIcon( HICON hIcon );
BOOL32 SetIcon( LPCTSTR lpIconName );
BOOL32 SetIcon( WORD nIDResource );
HICON GetIcon() const;
void HideIcon();
void ShowIcon();
void DeleteIcon();
// 关于通知窗口
BOOL32 SetNotificationWnd( CWnd* pNotifyWnd );
CWnd* GetNotificationWnd() const;
CPoint GetTrayCursorPos();
// 自定义消息处理函数
virtual LRESULT OnIconNotification( WPARAM wParam, LPARAM lParam );
protected:
NOTIFYICONDATA m_tnd; // 数据结构,请参考在线帮助
CPoint m_trayCursorPos; // 托盘响应WM_MOUSEMOVE时的鼠标坐标
BOOL32 m_bProcessingBtnMsg; // 是否在处理右键单击或左键双击托盘消息,此时应将消息盒子提示窗口掩藏掉
};
#endif
CTrayIcon类的cpp源文件如下:
#include "stdafx.h"
#include "trayicon.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CTrayIcon::CTrayIcon()
: m_trayCursorPos( CPoint(0, 0) )
, m_bProcessingBtnMsg( FALSE )
{
memset( &m_tnd, 0, sizeof(m_tnd) );
}
CTrayIcon::CTrayIcon( CWnd* pWnd, WORD uCallbackMessage, LPCTSTR szToolTip, HICON icon, WORD uID )
{
Create( pWnd, uCallbackMessage, szToolTip, icon, uID );
}
CTrayIcon& CTrayIcon::Instance()
{
static CTrayIcon s_hInstance;
return s_hInstance;
}
CTrayIcon::~CTrayIcon()
{
HideIcon();
DeleteIcon();
}
BOOL32 CTrayIcon::Create( CWnd* pWnd, WORD uCallbackMessage, LPCTSTR szToolTip, HICON icon, WORD uID )
{
BOOL32 bEnabled = FALSE;
// 文件只能使用在WINDOW 95以上的版本中
VERIFY( bEnabled = ( GetVersion() & 0xff ) >= 4 );
if ( !bEnabled )
{
uilog( _T("[CTrayIcon::Create] os version below WINDOW 95") );
return FALSE;
}
// 确认通知窗口有效
VERIFY( bEnabled = (pWnd && ::IsWindow(pWnd->GetSafeHwnd())) );
if ( !bEnabled )
{
uilog( _T("[CTrayIcon::Create] handle of main window is invalid") );
return FALSE;
}
// 确认自定义消息大于WM_USER
ASSERT( uCallbackMessage >= WM_USER );
// 确定提示文本长度小于64
ASSERT( _tcslen( szToolTip ) <= 64 );
// 定义NOTIFYICONDATA结构的数据项
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 );
// 设置图标
bEnabled = Shell_NotifyIcon( NIM_ADD, &m_tnd );
if ( !bEnabled )
{
uilog( _T("[CTrayIcon::Create] Shell_NotifyIcon[NIM_ADD] failed") );
}
return bEnabled;
}
void CTrayIcon::DeleteIcon()
{
m_tnd.uFlags = 0;
Shell_NotifyIcon( NIM_DELETE, &m_tnd );
}
void CTrayIcon::HideIcon()
{
m_tnd.uFlags = NIF_ICON;
Shell_NotifyIcon( NIM_DELETE, &m_tnd );
}
void CTrayIcon::ShowIcon()
{
m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
Shell_NotifyIcon( NIM_ADD, &m_tnd );
}
BOOL32 CTrayIcon::SetIcon( HICON hIcon )
{
if ( hIcon == NULL )
{
WriteTrayIconLog( _T("[CTrayIcon::SetIcon(HICON hIcon)]hIcon == NULL"));
}
else
{
WriteTrayIconLog( _T("[CTrayIcon::SetIcon(HICON hIcon)]hIcon = %d"), hIcon );
}
m_tnd.uFlags = NIF_ICON;
m_tnd.hIcon = hIcon;
BOOL32 bRet = Shell_NotifyIcon( NIM_MODIFY, &m_tnd );
if ( !bRet )
{
WriteTrayIconLog( _T("[CTrayIcon::SetIcon(HICON hIcon)]Shell_NotifyIcon(NIM_MODIFY-NIF_ICON) failed, lasterrid: %d"), GetLastError() );
}
return bRet;
}
BOOL32 CTrayIcon::SetIcon( LPCTSTR lpszIconName )
{
WriteTrayIconLog( _T("[CTrayIcon::SetIcon(LPCTSTR lpszIconName)]lpszIconName = %s"), lpszIconName );
HICON hIcon = AfxGetApp()->LoadIcon( lpszIconName );
return SetIcon( hIcon );
}
BOOL32 CTrayIcon::SetIcon( WORD nIDResource )
{
WriteTrayIconLog( _T("[CTrayIcon::SetIcon(WORD nIDResource)]nIDResource = %d"), nIDResource );
HICON hIcon = AfxGetApp()->LoadIcon( nIDResource );
return SetIcon( hIcon );
}
HICON CTrayIcon::GetIcon() const
{
HICON hIcon = NULL;
hIcon = m_tnd.hIcon;
return hIcon;
}
BOOL32 CTrayIcon::SetTooltipText( LPCTSTR pszTip )
{
m_tnd.uFlags = NIF_TIP;
_tcscpy( m_tnd.szTip, pszTip );
return Shell_NotifyIcon( NIM_MODIFY, &m_tnd );
}
BOOL32 CTrayIcon::SetTooltipText( WORD nID )
{
CString strText;
VERIFY( strText.LoadString( nID ) );
return SetTooltipText( strText );
}
CString CTrayIcon::GetTooltipText() const
{
CString strText;
strText = m_tnd.szTip;
return strText;
}
BOOL32 CTrayIcon::SetNotificationWnd( CWnd* pWnd )
{
ASSERT( pWnd && ::IsWindow( pWnd->GetSafeHwnd() ) );
m_tnd.hWnd = pWnd->GetSafeHwnd();
m_tnd.uFlags = 0;
return Shell_NotifyIcon( NIM_MODIFY, &m_tnd );
}
CWnd* CTrayIcon::GetNotificationWnd() const
{
return CWnd::FromHandle( m_tnd.hWnd );
}
LRESULT CTrayIcon::OnIconNotification( WPARAM wParam, LPARAM lParam )
{
if ( WM_MOUSEMOVE == lParam )
{
// 鼠标移动消息
return 0;
}
if ( wParam != m_tnd.uID )
{
return 0L;
}
// 单击右键弹出菜单
if ( WM_RBUTTONUP == LOWORD(lParam) )
{
// 右键弹起消息处理
}
else if ( WM_LBUTTONDOWN == LOWORD(lParam) || WM_LBUTTONDBLCLK == LOWORD(lParam) )
{
// 单击或者双击消息处理
}
m_bProcessingBtnMsg = FALSE;
}
return 1;
}
CPoint CTrayIcon::GetTrayCursorPos()
{
return m_trayCursorPos;
}
调用CTrayIcon::Create接口创建图标,创建时第一个参数是接收托盘通知消息的窗口,第二个参数是托盘被操作时回调的窗口自定义消息id,后面几个参数是用来设置托盘图标的提示文字和图标icon的,相关代码如下:
// 利用图标资源的ID去创建托盘图标
BOOL32 CreateTrayIcon( WORD nIDResource )
{
BOOL32 bSuccess = FALSE;
HICON hIcon = LoadIcon( AfxGetResourceHandle(), MAKEINTRESOURCE( nIDResource ) );
bSuccess = CTrayIcon::Instance().Create( this, WM_MY_TRAY_NOTIFICATION, _T("托盘图标提示文字"), hIcon, IDI_ICON_SYSTEM );
CTrayIcon::Instance().SetIcon( hIcon );
CTrayIcon::Instance().ShowIcon();
return bSuccess;
}
从创建托盘图标的代码可以看出,回调给指定窗口的托盘图标操作消息是自定义消息,是用户在创建托盘图标时指定的。先添加自定义消息的映射,接收到自定义消息,然后投递到CTrayIcon::OnIconNotification接口中去处理。相关代码如下:
LRESULT OnTrayNotification( WPARAM wParam, LPARAM lParam )
ON_MESSAGE( WM_MY_TRAY_NOTIFICATION, OnTrayNotification )
LRESULT CMainFrameWnd::OnTrayNotification( WPARAM wParam, LPARAM lParam )
{
return CTrayIcon::Instance().OnIconNotification( wParam, lParam );
}