一、闪动任务栏,提醒用户该窗口需要操作
这个很简单,直接在需要提醒用户的地方加入这一句就好了:
this->FlashWindowEx(FLASHW_TRAY | FLASHW_TIMERNOFG, 0, 0); // 仅任务栏,闪烁直到窗口激活,默认频率
CWnd::FlashWindowEx第一个参数是闪动方式:
FLASHW_CAPTION 闪动标题栏
FLASHW_TRAY 闪动任务栏
FLASHW_ALL 闪烁标题栏和任务栏
FLASHW_STOP 停止闪烁
FLASHW_TIMER 一直闪烁,直到FLASHW_STOP
FLASHW_TIMERNOFG 一直闪烁,直到窗口被切换到前台
第二个参数是闪烁次数,第三个参数是闪烁间隔毫秒数,这里都写0。
效果:
二、在任务栏显示进度(Win7)
Windows 7 中带来了超级任务栏,其中一个功能便是显示进度,它在Visual C++中可以利用ITaskbarList3实现。它是一个COM组件,需要手工创建。通常在"TaskbarButtonCreated"这个注册消息(任务栏按钮创建完毕)中实例化。
在Visual C++ 2010中的CFrameWnd中已经集成了这个功能,直接调用SetProgressValue和SetProgressState就可以了,但是对话框CDialog或CDialogEx仍然不能这么做。如果你使用的是Visual Studio 2008或以前的版本,那么需要安装Windows 7 SDK,或者手工移植ITaskbarList3。
首先在对话框的类声明里加入以下几句:
CComQIPtr<itaskbarlist3> m_tbl; // 任务栏:ITaskBarList3实例指针
LRESULT OnTaskbarButtonCreated(WPARAM wParam, LPARAM lParam); // 任务栏:"TaskbarButtonCreated"消息</itaskbarlist3>
然后修改对话框的CPP文件:
const UINT WM_TASKBAR_BUTTON_CREATED = RegisterWindowMessage("TaskbarButtonCreated"); // 任务栏:注册消息
BEGIN_MESSAGE_MAP(CTaskBarTestDlg, CDialog)
// ... 其它消息映射 ...
ON_REGISTERED_MESSAGE(WM_TASKBAR_BUTTON_CREATED, OnTaskbarButtonCreated) // 任务栏:映射消息
END_MESSAGE_MAP()
为消息映射添加代码:
LRESULT CTaskBarTestDlg::OnTaskbarButtonCreated(WPARAM wParam, LPARAM lParam) // 任务栏图标创建时:ITaskBarList3实例化COM对象
{
// RegisterWindowsMessage("TaskbarButtonCreated") 注册的消息,ON_REGISTERED_MESSAGE(msg, fn) 登记
// 在任务栏按钮创建完毕时,"TaskbarButtonCreated"会被触发,
// 这个时候就可以实例化ITaskbarList3对象了
m_tbl.Release(); // 如果有的话,释放以前的
m_tbl.CoCreateInstance(CLSID_TaskbarList); // 任务栏:构造ITaskbarList3类型COM对象
return TRUE;
}
最后添加WM_DESTROY消息映射,释放ITaskbarList3实例(因为MFC在对话框析构之前调用了CoUninitialize(),不及时释放会崩溃):
void CTaskBarTestDlg::OnDestroy() // 窗口销毁时:ITaskBarList3析构COM对象
{
CDialog::OnDestroy();
m_tbl.Release(); // 任务栏:析构COM对象(必须在调用CoUnintialize()之前,不能等待CComQIPtr析构函数,否则会崩溃)
}
这样,我们就可以使用m_tbl的成员函数SetProgressValue和SetProgressState来在任务栏显示进度了:
void CTaskBarTestDlg::OnBnClickedSetProgress()
{
UpdateData(true);
if (m_tbl != NULL) {
m_tbl->SetProgressValue(m_hWnd, m_slider, 100); // 设置任务栏进度
}
}
void CTaskBarTestDlg::OnBnClickedButton1()
{
if (m_tbl != NULL) {
m_tbl->SetProgressState(m_hWnd, TBPF_NORMAL); // 设置任务栏进度状态:正常 - 绿色
}
}
void CTaskBarTestDlg::OnBnClickedButton2()
{
if (m_tbl != NULL) {
m_tbl->SetProgressState(m_hWnd, TBPF_ERROR); // 设置任务栏进度状态:错误 - 红色
}
}
void CTaskBarTestDlg::OnBnClickedButton3()
{
if (m_tbl != NULL) {
m_tbl->SetProgressState(m_hWnd, TBPF_PAUSED); // 设置任务栏进度状态:暂停 - 黄色
}
}
void CTaskBarTestDlg::OnBnClickedButton4()
{
if (m_tbl != NULL) {
m_tbl->SetProgressState(m_hWnd, TBPF_INDETERMINATE); // 设置任务栏进度状态:不确定 - 绿色滚动
}
}
void CTaskBarTestDlg::OnBnClickedButton5()
{
if (m_tbl != NULL) {
m_tbl->SetProgressState(m_hWnd, TBPF_NOPROGRESS); // 设置任务栏进度状态:清除进度
}
}
效果:
1. 正常 - 绿色
2. 错误 - 红色
3. 暂停 - 黄色
4. 不确定 - 绿色滚动
5. 清除进度
三、在通知区域显示图标
这是一个烂大街的老技术了,但是还是很实用的。操作通知区域图标一般使用Shell_NotifyIcon()函数,该函数需要两个参数,第一个参数是操作命令,第二个参数是一个NOTIFYICONDATA结构。
第一个参数的常用取值:
NIM_ADD 添加图标
NIM_DELETE 删除图标
NIM_MODIFY 修改图标参数
结构体NOTIFYICONDATA的成员:
cbSize 结构体大小(用sizeof获得)
hWnd 窗口句柄
uID 通知区域图标ID
uFlags 表明具体哪些其他成员为合法数据,有NIF_ICON、NIF_MESSAGE、NIF_TIP、NIF_STATE、NIF_INFO、NIF_GUID等,在这里我们只用到NIF_ICON、NIF_MESSAGE、NIF_TIP三个标志。
NIF_ICON代表成员:
hIcon表示要显示的图标句柄
NIF_MESSAGE代表成员:
uCallbackMessage表示鼠标点击图标触发的消息(可自定义消息,通常定义为WM_USER+x)
NIF_TIP代表成员:
szTip表示鼠标悬停在图标上显式的提示文字
由于explorer崩溃以后系统不会储存图标,因此需要程序捕捉explorer崩溃重启,手动重建图标,方法是捕获"TaskbarCreated"注册消息。
创建图标的代码:
// 自定义图标消息
#define WM_ICON_MESSAGE (WM_USER + 100)
void CTaskBarTestDlg::OnBnClickedShowTray()
{
NOTIFYICONDATA tnd;
tnd.cbSize = sizeof(NOTIFYICONDATA); // 自身大小
// 窗口句柄
tnd.hWnd = this->m_hWnd;
// 通知图标ID
tnd.uID = IDR_MAINFRAME;
// 标志位:消息 + 图标 + 工具提示
tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
// 消息
tnd.uCallbackMessage = WM_ICON_MESSAGE;
// 图标
tnd.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
// 提示
strcpy(tnd.szTip,"测试程序");
Shell_NotifyIcon(NIM_ADD, &tnd); // 添加图标
m_is_icon_show = true;
}
删除图标的代码:
void CTaskBarTestDlg::OnBnClickedHideTray()
{
NOTIFYICONDATA tnid;
tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = this->m_hWnd;
tnid.uID = IDR_MAINFRAME;
tnid.uFlags = NULL;
Shell_NotifyIcon(NIM_DELETE, &tnid); // 删除图标
m_is_icon_show = false;
}
explorer崩溃重建图标:
const UINT WM_TASKBAR_CREATED = RegisterWindowMessage("TaskbarCreated"); // 通知图标:注册消息
BEGIN_MESSAGE_MAP(CTaskBarTestDlg, CDialog)
// ... 其它消息映射 ...
ON_REGISTERED_MESSAGE(WM_TASKBAR_CREATED, OnTaskbarCreated) // 通知图标:映射消息
END_MESSAGE_MAP()
// ... 其它代码 ...
LRESULT CTaskBarTestDlg::OnTaskbarCreated(WPARAM wParam, LPARAM lParam) // 当explorer崩溃时重建图标
{
// RegisterWindowsMessage("TaskbarCreated") 注册的消息,ON_REGISTERED_MESSAGE(msg, fn) 登记
if (m_is_icon_show)
OnBnClickedShowTray();
return TRUE;
}
图标点击消息:
BEGIN_MESSAGE_MAP(CTaskBarTestDlg, CDialog)
// ... 其它消息映射 ...
ON_MESSAGE(WM_ICON_MESSAGE, OnIconMessage) // 通知图标:映射消息
END_MESSAGE_MAP()
// ... 其它代码 ...
LRESULT CTaskBarTestDlg::OnIconMessage(WPARAM wParam, LPARAM lParam) // 自定义的通知图标消息WM_ICON_MESSAGE
{
// #define WM_ICON_MESSAGE (WM_USER + 100) 定义的消息,ON_MESSAGE(msg, fn) 登记
UINT uID = (UINT) wParam;
UINT uMouseMsg = (UINT) lParam;
if (uID = IDR_MAINFRAME) {
switch (uMouseMsg) {
case WM_LBUTTONDBLCLK: // 双击时:显示窗口并隐藏图标
this->SetForegroundWindow();
this->ShowWindow(SW_SHOW);
OnBnClickedHideTray();
return TRUE;
case WM_RBUTTONDOWN: // 右击时:显示弹出菜单
CMenu menu, *pMenu;
menu.LoadMenu(IDR_MENU1); // 加载菜单
pMenu = menu.GetSubMenu(0); // 获取子菜单
POINT ptPos;
GetCursorPos(&ptPos); // 获取鼠标指针
pMenu->SetDefaultItem(ID_POP_SHOW_MAIN); // 设置默认项
this->SetForegroundWindow(); //这一行代码很重要,否则右键菜单工作不正常。详见msdn说明: http://support.microsoft.com/kb/135788
pMenu->TrackPopupMenu(
TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
ptPos.x, ptPos.y,
this); // 弹出菜单
return TRUE;
}
}
return FALSE;
}
效果:
==========================================================
示例源码和程序:
TaskBarTest.rar
303.52KB
RAR
86次下载
运行界面: