A.第一种方法是通过MFC来实现的,从网上找的,red已经注明。
如果我们在程序最小化时采用在系统任务栏中的小图标,就象金山词霸一样,单击左键可以
实现最大最小化,单击右键有快捷菜单,那么整个程序会显的很简洁。
采用SDK的Shell_NotifyIcon等API可以实现系统任务栏的小图标,但是程序员必须仔细理解
这些API的具体用法,Chris Maunder 开发的系统任务栏类CSystemTray封装了这些API的功能,
使MFC程序员可以方便的实现具有系统任务栏小图标的程序。
---- CsytemTray的功能很多,看一看它的成员函数就可以知道其大致功能了。
BOOL Enabled() { return m_bEnabled; }
BOOL Visible() { return !m_bHidden; }
//Create the tray icon
Create(CWnd* pWnd, UINT uCallbackMessage,
LPCTSTR szTip, HICON icon, UINT uID);
//Change or retrieve the Tooltip text
BOOL SetTooltipText(LPCTSTR pszTooltipText);
BOOL SetTooltipText(UINT nID);
CString GetTooltipText() const;
//Change or retrieve the icon displayed
BOOL SetIcon(HICON hIcon);
BOOL SetIcon(LPCTSTR lpIconName);
BOOL SetIcon(UINT nIDResource);
BOOL SetStandardIcon(LPCTSTR lpIconName);
BOOL SetStandardIcon(UINT nIDResource);
HICON GetIcon() const;
void HideIcon();
void ShowIcon();
void RemoveIcon();
void MoveToRight();
//Change or retrieve the window to
send notification messages to
BOOL SetNotificationWnd(CWnd* pNotifyWnd);
CWnd* GetNotificationWnd() const;
下面是实现步骤:
(1)首先在Project中加入CsystemTray类的.cpp和.h文件,这样在Workspace的
ClassView中可以看到CsystemTray类。
(2)然后在CframeWnd的派生类的头文件中
a.加入WM_ICON_NOTIFY 的消息定义
#define WM_ICON_NOTIFY WM_USER+1
b.在CframeWnd的派生类中添加变量
CSystemTray m_TrayIcon;
c.在CframeWnd的派生类的CPP文件中添加消息映射
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
... ...
ON_MESSAGE(WM_ICON_NOTIFY, OnTrayNotification)
END_MESSAGE_MAP()
(3)在CframeWnd的派生类中添加成员函数
LRESULT CMainFrame::OnTrayNotification(WPARAM wParam, LPARAM lParam)
{
return m_TrayIcon.OnTrayNotification(wParam, lParam);
}
(4)定义快捷菜单
在MENU中添加新菜单IDR_POPUP_MENU,可以如一般的菜单一样从ClassWizard中定义其响应。
(5)在CsystemTray中修改OnTrayNotification函数,
定义你希望实现的效果,如单击左键可以实现最大最小化,单击右键有快捷菜单等功能。
LRESULT CSystemTray::OnTrayNotification(UINT wParam, LONG lParam)
{
//Return quickly if its not for this tray icon
if (wParam != m_tnd.uID)
return 0L;
CMenu menu, *pSubMenu;
//定义单击右键有快捷菜单
if (LOWORD(lParam) == WM_RBUTTONUP)
{
if (!menu.LoadMenu(m_tnd.uID))
return 0;
if (!(pSubMenu = menu.GetSubMenu(0)))
return 0;
// Make first menu item the default (bold font)
::SetMenuDefaultItem(pSubMenu- >m_hMenu, 0, TRUE);
//Display and track the popup menu
CPoint pos;
GetCursorPos(&pos);
::SetForegroundWindow(m_tnd.hWnd);
::TrackPopupMenu(pSubMenu->m_hMenu, 0, pos.x,
pos.y, 0, m_tnd.hWnd, NULL);
// BUGFIX: See "PRB: Menus for Notification
Icons Don't Work Correctly"
::PostMessage(m_tnd.hWnd, WM_NULL, 0, 0);
menu.DestroyMenu();
}
//定义双击左键有产生单击快捷菜单第一项功能的响应
else if (LOWORD(lParam) == WM_LBUTTONDBLCLK)
{
if (!menu.LoadMenu(m_tnd.uID)) return 0;
if (!(pSubMenu = menu.GetSubMenu(0))) return 0;
// double click received, the default action is to execute first menu item
::SetForegroundWindow(m_tnd.hWnd);
::SendMessage(m_tnd.hWnd, WM_COMMAND,
pSubMenu->GetMenuItemID(0), 0);
menu.DestroyMenu();
}
//定义单击左键为最小化或恢复窗口
else if (LOWORD(lParam) == WM_LBUTTONUP)
{
if(AfxGetMainWnd()->IsIconic()!=0)
{
EnableWindow(m_tnd.hWnd,TRUE);
ShowWindow(m_tnd.hWnd,SW_SHOW);
ShowWindow(m_tnd.hWnd,SW_RESTORE);
}
else
{
ShowWindow(m_tnd.hWnd,SW_SHOWMINIMIZED);
EnableWindow(m_tnd.hWnd,FALSE);
ShowWindow(m_tnd.hWnd,SW_HIDE);
}
}
return 1;
}
(6)在CmainFrame的派生类中添加WM_SIZE的消息响应函数,这可以实现程序最小化时
只在系统任务栏中有一个小图标,而不会在一般任务栏中有显示
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
if(nType==SIZE_MINIMIZED)
{
EnableWindow(FALSE);
ShowWindow(SW_HIDE);
}
}
看起来似乎这样实现步骤也不少,但是当我们再开发新的功能时会很方便,程序会更容易
理解与开发。如我们可以很方便实现动态小图标。
a.我们只需在CmainFrame的派生类中添加一个定时器,
SetTimer(IDW_TIMER1,500,NULL);
icon_id=0;
b.对定时发出的WM_TIME消息进行处理,例如时间到了就换一个图标,图标的变化可以根据
自己的喜好及实际情况定义,此处有3个图标轮流变化。
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
//change the icon
//icon_id from 0 to 2 every 0.5s
if(nIDEvent ==IDW_TIMER1)
{
if(icon_id==0)
{
hIcon=AfxGetApp()->LoadIcon(IDR_ICON0);
icon_id++;
}
else if(icon_id==1)
{
hIcon=AfxGetApp()->LoadIcon(IDR_ICON1);
icon_id++;
}
else if(icon_id=2)
{
hIcon=AfxGetApp()->LoadIcon(IDR_ICON2);
icon_id=0;
}
m_TrayIcon.SetIcon(hIcon);
}
CFrameWnd::OnTimer(nIDEvent);
}
B.第二种方法是通过消息去处理;
创建的基于对话框,看下面说明:
a.在WM_SIZE 消息里面处理有检测到最小化的动作时,作如下的操作:
主要是从代码中摘取的,看主要的代码就好了:
case WM_SIZE:
if(wParam == SIZE_MINIMIZED)//if wparam == minimized,then add the icon into the taskbar only;
{
if(!g_bAddIcon)
{
if(!AddIconToTaskbar(hDlg))
MessageBox(0,"Add Icon to task bar ,failed!",0,0);
}
ShowWindow(hDlg,SW_HIDE);//hide the window;
}
break;
b.在WM_COMMAND消息中要remove掉图标;
switch (LOWORD(wParam))
{
case IDCANCEL:
if (!g_bColor)
{
KillTimer(hDlg, 1);
}
portio.ShutdownDriver(szDriverName);
CloseHandle(hLogFile);
g_bRemove = TRUE;
AddIconToTaskbar(hDlg);
DeleteObject(hBrush);
DeleteObject(hCurrentFont);
EndDialog(hDlg, FALSE);
return TRUE;
}
C.关键函数 AddIconTaskBar(HWND hwnd),主要处理如下:
BOOL AddIconToTaskbar(HWND hwnd)
{
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
strcpy(nid.szTip, "XXX");
nid.hWnd = hwnd;
nid.uID = 100;
nid.uFlags = NIF_ICON | NIF_MESSAGE;
nid.hIcon = LoadIcon(gst_hInstance, MAKEINTRESOURCE(IDI_TEMP));
nid.uCallbackMessage = WM_TASKMOUSE;//here to catch the mouse move message
if (nid.hIcon == NULL)
{
MessageBox(0, "Can not add icon ,failed!", 0, 0);
return FALSE;
}
if (!g_bRemove)
{
if (Shell_NotifyIcon(NIM_ADD, &nid))//add the icon into the taskbar
{
g_bAddIcon = TRUE;
return TRUE;
}
else
return FALSE;
}
else
{
Shell_NotifyIcon(NIM_DELETE, &nid);//delete the icon from the taskbar
return TRUE;
}
}
here, 处理鼠标的动作如下,比较粗糙:
case WM_TASKMOUSE:
if( lParam == WM_LBUTTONDBLCLK)
{
ShowWindow(hDlg,SW_SHOWNORMAL);//double left click to show the window
}
break;
转载请注明,谢谢合作!
red 2010/02/10