<script type="text/javascript">function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>
托盘在任务栏的右下角,下图就是一个托盘(抓那个图标就是之后的文章要介绍的抓图程序,不要BS我的审美),英文名字很酷--Tray
![](https://p-blog.csdn.net/images/p_blog_csdn_net/smalllixin/tray.JPG)
这是个看起来很诱人的功能。
我们只需要了解:
一个结构NOTIFYICONDATA
一个API Shell_NotifyIcon
就可以实现它,知道这个API后你就可以去msdn查查怎么用,当然如果你很懒得话就用我将要列出来的这个类吧,很容易使用。
#include
"
shellapi.h
"
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
class
CTrayIcon
//
添加托盘图标到系统托盘类
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
public:
CTrayIcon(void);
~CTrayIcon(void);
public:
void Init( HWND hWnd ,DWORD uID ,UINT nMsg ,const TCHAR * msg ); //初始化托盘图标
void ShowIcon( ); //添加托盘图标到系统托盘
BOOL ShowBalloon( LPCTSTR InfoTitle , LPCTSTR Info , UINT InfoType );
void DeleteIcon( ); //删除托盘图标
private:
NOTIFYICONDATA m_TrayIcon; //托盘图标类型的变量
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*
* All rights reserved.
* Li Xin
* 文件名称:TrayIcon.cpp
* 文件标识:
* 摘 要:实现托盘图标
*/
#include
"
StdAfx.h
"
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#include
"
TrayIcon.h
"
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*******************************************************************************
* 函数名:CTrayIcon
* 功 能:添加托盘图标类的构造函数
* 返回值:无
* 参数列表:无
********************************************************************************/
CTrayIcon::CTrayIcon(
void
)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/********************************************************************************
* 函数名:CTrayIcon
* 功 能:添加托盘图标类的析构函数
* 返回值:无
* 参数列表:无
********************************************************************************/
CTrayIcon::
~
CTrayIcon(
void
)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*******************************************************************************
* 函数名:Init
* 功 能:初始化托盘图标
* 返回值:void
* 参数列表:)hWnd 类型:HWND 说明:主窗口句柄
* 2)uID 类型:DWORD 说明:托盘图标id
3)nMsg 类型:UINT 说明:Tray的事件会通过此消息通知应用程序
4)str 类型:TCHAR 说明:鼠标放在图标上后显示的文本信息
*******************************************************************************/
void
CTrayIcon::Init( HWND hWnd ,DWORD uID ,UINT nMsg ,
const
TCHAR
*
msg )
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
m_TrayIcon.cbSize = sizeof( NOTIFYICONDATA ); //结构所占的字节数,必须用结构的大小来初始化
m_TrayIcon.hWnd = hWnd; //接受Tray图标消息的窗口句柄
m_TrayIcon.uID = uID; //由应用程序定义的图标ID
m_TrayIcon.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; //用来鉴别那些需要改变其值的域,NIF_ICON表示hIcon有效,可用来修改图标,NIF_MESSAGE表示uCallbackMessage有效,用来定义消息,NIF―TIP表示szTip参数有效,可修改工具提示。
m_TrayIcon.uCallbackMessage = nMsg; // 应用程序定义的消息
m_TrayIcon.hIcon = AfxGetApp( )->LoadIcon( uID ); //Tray图标的句柄
lstrcpy( m_TrayIcon.szTip ,msg ); //szTip[64]为工具提示的文本
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/******************************************************************************
* 函数名:ShowIcon
* 功 能:添加托盘图标到系统托盘
* 返回值:void
* 参数列表:无
*******************************************************************************/
void
CTrayIcon::ShowIcon( )
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
Shell_NotifyIcon(NIM_ADD,&m_TrayIcon); //添加最小化图标
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/******************************************************************************
* 函数名:DeleteIcon
* 功 能:删除托盘图标
* 返回值:void
* 参数列表:无
*******************************************************************************/
void
CTrayIcon::DeleteIcon( )
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
Shell_NotifyIcon( NIM_DELETE,&m_TrayIcon ); //删除最小化图标
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/******************************************************************************
* 函数名:ShowBalloon
* 功 能:显示气球对话框
* 返回值:void
* 参数列表:)InfoTitle 类型:LPCTSTR 说明:信息标题
2)Info 类型:LPCTSTR 说明:信息内容
3)InfoType 类型:UINT 说明:信息类型
*******************************************************************************/
BOOL CTrayIcon::ShowBalloon( LPCTSTR InfoTitle , LPCTSTR Info , UINT InfoType )
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
m_TrayIcon.uFlags = NIF_INFO;
m_TrayIcon.uTimeout = 1500;
m_TrayIcon.dwInfoFlags = NIIF_INFO;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
lstrcpy ( m_TrayIcon.szInfo, Info );
lstrcpy ( m_TrayIcon.szInfoTitle, InfoTitle );
return Shell_NotifyIcon(NIM_MODIFY, &m_TrayIcon);
}
使用起来很容易:
定义一个自定义消息
#define WM_TRAYPROC WM_USER+123
CTrayIcon tray;声明一个全局变量
在你主对话框的OnInitDialog中添加
tray.Init(m_hWnd, IDI_TRAY, WM_TRAYPROC, L"按Esc退出抓图");
tray.ShowIcon();
tray.ShowBalloon(L"Notify", L"按Ctrl + Shit + M 键截图/r截图模式:/rEsc取消截图/r回车复制进剪切板", NIF_INFO);
在OnClose中调用
tray.DeleteIcon();
其中ShowBalloon是显示一个气球,传说中XP下有个Bug,这个气球本来能够定时显示多长时间后自动关闭,但是XP下这个功能不好使。
Okay! 我们平时所看到的托盘都能够相应操作,这个是如何实现的呢?刚刚定义了一个WM_TRAYPROC消息,就是做这个事情的。
需要在对话框中处理消息循环,参考下面的代码可以处理消息。
这是个基本的封装,你可以根据msdn的信息来扩展它。
Okay, that’s all!想为你的程序加上托盘功能么?Try it! Enjoy it!
LRESULT C
**
Dlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
if (message == WM_TRAYPROC)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
UINT uMouseMsg; //鼠标动作
uMouseMsg = (UINT) lParam;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
if (uMouseMsg == WM_LBUTTONDOWN) //鼠标左键响应
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//if (!IsWindowVisible())
//{
// SetForegroundWindow();
// ShowWindow(SW_SHOW); //显示主窗口
//}
//else
//{
// ShowWindow(SW_HIDE);
//}
}
else if (uMouseMsg == WM_RBUTTONUP) //鼠标右键响应
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
CPoint Point;
GetCursorPos( &Point );
SetForegroundWindow();
m_trayMenuPop->TrackPopupMenu(TPM_RIGHTALIGN | TPM_BOTTOMALIGN, Point.x , Point.y , this , NULL);
AfxGetMainWnd()->PostMessage(WM_NULL , 0 , 0);
}
}
else if(message == WM_ACTIVATE_CAPTURE)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
screenDlg.SetOverPopWindow(NULL, SW_HIDE);
PopScreenCaptureDlg();
}
return CDialog::WindowProc(message, wParam, lParam);
}