所谓最小化至托盘,其真实的意义是:应用程序Hide掉,并在托盘区创建图标而已。当双击图标时,再将应用程序Show出来,并将托盘图标删除(也可以保留,不一定要删除)。
有了这个观念,按照以下的几个步骤就可以很容易的处理托盘图标:
1. 为应用程序准备一个托盘的图标资源(使用默认的图标资源IDR_MAINFRAME亦可)
2. 在应用程序窗口OnCreate(或者对话框OnInitDialog)时添加托盘图标。这需要一个API函数Shell_NotifyIcon完成:
需要做的是准备一个NOTIFYICONDATA结构,该结构描述了托盘图标的外貌以及和应用程序的关联,并将它传递给Shell_NotifyIcon。
// 配置NOTIFYICONDATA结构
NOTIFYICONDATA notifyIconData;
ZeroMemory( ¬ifyIconData, sizeof( notifyIconData ) );
notifyIconData.cbSize = sizeof( notifyIconData );
//... notifyIconData.uFlags使特定成员有效
//... NIF_ICON 使hIcon有效
//... NIF_MESSAGE 使uCallbackMessage有效
//... NIF_TIP 使szTip有效
notifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
//... notifyIconData.hIcon图标资源句柄,描述图标如何被绘制
//... notifyIconData.uID用于管理图标(日后修改或删除图标就靠他了,通常使用图标句柄对应的ID即可)
notifyIconData.hIcon = LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_MAINFRAME ) );
notifyIconData.uID = IDR_MAINFRAME;
//... 表示当图标上有鼠标事件时,全部发送至窗口notifyIconData.hWnd并映射至notifyIconData.uCallbackMessage消息。
notifyIconData.hWnd = m_hWnd;
notifyIconData.uCallbackMessage = WM_TRAY;
//... 表示鼠标悬浮其上的提示信息
lstrcpy( notifyIconData.szTip, _T( "这是示例图标" ) );
// 添加图标,NIM_ADD标志表示添加,NIM_MODIFY表示修改,NIM_DELETE表示删除。
Shell_NotifyIcon( NIM_ADD, ¬ifyIconData );
3. 处理窗口最小化。响应窗口的WM_SYSMESSAGE消息并在最小化时简单地将主窗口Hide掉:
if ( nID == SC_MINIMIZE ) { // 你也可以选择同样方式处理SC_CLOSE
ShowWindow( SW_HIDE );
return;
}
4. 响应托盘图标鼠标消息( 该消息在添加图标时被notifyIconData.uCallbackMessage指定 )
LRESULT CYourWnd::OnTray( WPARAM wParam, LPARAM lParam )
{
// 不要处理非本窗口图标消息
if ( wParam != IDR_MAINFRAME ) {
return 1;
}
// 左键双击,隐藏或显示窗口
if ( lParam == WM_LBUTTONDBLCLK ) {
ShowWindow( IsWindowVisible() ? SW_HIDE : SW_SHOW );
}
// 右键单击,打开弹出菜单
else if ( lParam == WM_RBUTTONUP ) {
// 设置为前台窗口以在单击非弹出菜单区域时使菜单自动消失
SetForegroundWindow();
POINT cursorPosition;
GetCursorPos( &cursorPosition );
// 自己创建一个弹出菜单
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu( MF_STRING, WM_DESTROY, _T( "关闭" ) );
menu.SetDefaultItem( 0, TRUE );
/* 你也可以使用菜单资源
CMenu menu;
menu.LoadMenu( IDR_MYCONTEXTMENU );
CMenu* contextMenu = menu.GetSubMenu( 0 );
*/
menu.TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
cursorPosition.x, cursorPosition.y, this );
}
return 0;
}
5. 在窗口销毁以前(相应OnDestroy)删除托盘图标。
void CYourWnd::OnDestroy()
{
CWnd::OnDestroy();
NOTIFYICONDATA notifyIconData;
ZeroMemory( ¬ifyIconData, sizeof( notifyIconData ) );
notifyIconData.cbSize = sizeof( notifyIconData );
notifyIconData.uID = IDR_MAINFRAME;
notifyIconData.hWnd = m_hWnd;
Shell_NotifyIcon( NIM_DELETE, ¬ifyIconData );
}