📄 vc++6_0中实现将应用程序的图标加入到windows的系统托盘中—编程爱好者网站http--www_programfan_com.htm
字号:
uID; <BR>// 应用程序中定义的托盘图标ID,此参数用作标识 <BR>UINT
uFlags;<BR>//设置属性,低三位有意义,0--7,如下: <BR>//第一位//#define
NIF_MESSAGE 0x1 <BR>// uCallbackMessage参数有效
<BR><BR>//第二位//#define NIF_ICON 0x2 // hIcon参数有效
<BR>//第三位//#define NIF_TIP 0x4 // szTip参数有效
<BR> <BR>UINT
uCallbackMessage; <BR>//
自定义的消息ID值,一定不要与以有的消息ID相重。 <BR>HICON hIcon;
<BR>//显示在系统托盘上的Icon的句柄,可以为系统的 IDI_WINLOGO等<BR>CHAR szTip[64];
// 用于图标显示的提示字符串<BR>}
NOTIFYICONDATA;<BR><BR> 为了接收到来自托盘的通知消息你可以将uCallbackMessage设定为你所定义的消息<BR> ID值,同时设定NIF_MESSAGE标志。这样当用户在你的托盘图标上移动或按下鼠标<BR> 时,Windows将发出消息:该消息的
messageID是你在uCallbackMessage中定义的<BR> 值;wParam是你定义的uID值;而lParam是鼠标事件(如WM_LBUTTONDOWN),这样你<BR> 的应用程序就能响应该事件了。
<BR> 因此,为了将自己的应用程序加入到系统托盘中,首先得建立一处理托盘通知消息<BR> 的窗口对象,然后将窗口对象与你自己的托盘通知消息联系起来并建立相应的托盘<BR> 通知消息映射机制,以便你的窗口对象能处理相应的事件。
<BR><BR> 可以看到结构体NOTIFYICONDATA中,其成员变量hWnd,uID,uFlags均用于在窗口对<BR> 象与你自己的托盘通知消息之间建立联系,而成员变量uCallbackMessage则必须是<BR> 对应于你的窗口对象的托盘通知消息ID值。
<BR><BR> 于是要完成的工作有:
<BR><BR> (1)建立一处理托盘通知消息的窗口对象;
<BR> (2)建立一结构体NOTIFYICONDATA变量,并给变量的相应域赋值以在托盘通知消<BR> 息与窗口对象之间建立联系;
<BR> (3)建立相应的托盘通知消息映射机制;
<BR> (4)调用Shell_NotifyIcon函数以在系统托盘中加入、修改或删除图标;
<BR> (5)当然别忘了在你的窗口对象中编写相应的事件响应函数。
<BR><BR> 因此,可以编写一C++类来实现以上功能以简化编程同时提高代码的可重用性。以<BR> 下为该类代码:
<BR><BR>class CTrayIcon : public CCmdTarget
{<BR>protected:<BR> DECLARE_DYNAMIC(CTrayIcon)<BR> NOTIFYICONDATA
m_nid; <BR>// Shell_NotifyIcon
函数中的结构参数<BR><BR>public:<BR> CTrayIcon(UINT
uID);<BR> ~CTrayIcon();<BR><BR> //
通过调用该成员函数来接收托盘通知消息<BR> void
SetNotificationWnd(CWnd* pNotifyWnd,<BR> UINT
uCbMsg);<BR><BR> // SetIcon
函数用来在系统托盘中加入、改变及删除图标。<BR> //要删除图标这样调用:SetIcon(0)<BR> BOOL
SetIcon(UINT uID); <BR> BOOL SetIcon(HICON hicon,
LPCSTR lpTip);<BR> BOOL SetIcon(LPCTSTR lpResName,
LPCSTR lpTip)<BR> {
<BR> return SetIcon(lpResName ?
<BR> AfxGetApp()->LoadIcon(lpResName):NULL,lpTip);<BR> }<BR> <BR> BOOL
SetStandardIcon(LPCTSTR lpszIconName,LPCSTR
lpTip)<BR> {<BR> return
SetIcon(::LoadIcon(NULL,lpszIconName),lpTip);<BR> }<BR><BR> virtual
LRESULT OnTrayNotification(WPARAM uID, LPARAM
lEvent);<BR>};<BR><BR>CTrayIcon::CTrayIcon(UINT
uID)<BR>{<BR> //初始化NOTIFYICONDATA结构变量<BR> memset(&m_nid,
0 , sizeof(m_nid));<BR> m_nid.cbSize =
sizeof(m_nid);<BR> m_nid.uID = uID;
<BR> AfxLoadString(uID, m_nid.szTip,
sizeof<BR> (m_nid.szTip));<BR>}<BR><BR>CTrayIcon::~CTrayIcon()<BR>{<BR> SetIcon(0);
// 从系统托盘中删除图标<BR>}<BR><BR>// 设定通知窗口,该窗口必须已被创建<BR>void
CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT
uCbMsg)<BR>{<BR> ASSERT(pNotifyWnd==NULL
||
::IsWindow(pNotifyWnd->GetSafeHwnd()));<BR><BR> m_nid.hWnd
= pNotifyWnd->GetSafeHwnd();<BR><BR>ASSERT(uCbMsg==0 ||
uCbMsg>=WM_USER);<BR>m_nid.uCallbackMessage =
uCbMsg;<BR>}<BR><BR>BOOL CTrayIcon::SetIcon(UINT uID)<BR>{
<BR> HICON hicon=NULL;<BR> if (uID)
{<BR> AfxLoadString(uID, m_nid.szTip,
sizeof(m_nid.szTip));<BR> hicon =
AfxGetApp()->LoadIcon(uID);<BR> }<BR> return
SetIcon(hicon,
NULL);<BR>}<BR><BR>//////////////////<BR>//<BR>BOOL
CTrayIcon::SetIcon(HICON hicon, LPCSTR lpTip)
<BR>{<BR> UINT msg;<BR> m_nid.uFlags =
0;<BR><BR> // 设定图标<BR> if (hicon)
{<BR> //
判断是要在系统托盘中增加还是要删除图标<BR> msg = m_nid.hIcon ?
NIM_MODIFY : NIM_ADD;<BR> m_nid.hIcon =
hicon;<BR> m_nid.uFlags |=
NIF_ICON;<BR> } else { //
删除图标<BR> if
(m_nid.hIcon==NULL)<BR> return
TRUE; //已被删除<BR> msg =
NIM_DELETE;<BR> }<BR> if
(lpTip)<BR> strncpy(m_nid.szTip, lpTip,
sizeof(m_nid.szTip));<BR> if
(m_nid.szTip[0])<BR> m_nid.uFlags |=
NIF_TIP;<BR><BR> if (m_nid.uCallbackMessage
&& m_nid.hWnd)<BR> m_nid.uFlags |=
NIF_MESSAGE;<BR><BR> BOOL bRet =
Shell_NotifyIcon(msg, &m_nid);<BR> if
(msg==NIM_DELETE || !bRet)<BR> m_nid.hIcon =
NULL; <BR> return bRet;<BR>}<BR><BR>//
缺省事件处理程序,该程序处理鼠标右击及双击事件。<BR>LRESULT
CTrayIcon::OnTrayNotification(WPARAM wID,<BR>LPARAM
lEvent)<BR>{<BR> if (wID!=m_nid.uID
||<BR> (lEvent!=WM_RBUTTONUP &&
lEvent!=WM_LBUTTONDBLCLK))<BR> return
0;<BR><BR> // 使用与托盘图标拥有同样ID号的菜单作为右键弹出菜单
<BR> // 并将菜单上的第一项作为缺省命令使用,<BR> //
缺省命令在WM_LBUTTONDBLCLK事件发生时被击发<BR> //
<BR> CMenu menu;<BR> if
(!menu.LoadMenu(m_nid.uID))<BR> return
0;<BR> CMenu* pSubMenu =
menu.GetSubMenu(0);<BR> if (!pSubMenu)
<BR> return 0;<BR><BR> if
(lEvent==WM_RBUTTONUP) {<BR><BR> //使菜单第一项为缺省项
(表现为粗体)<BR> ::SetMenuDefaultItem(pSubMenu->m_hMenu,
0, TRUE);<BR><BR> //
在鼠标的当前位置弹出菜单。<BR> CPoint
mouse;<BR> GetCursorPos(&mouse);<BR> ::SetForegroundWindow(m_nid.hWnd);
<BR> ::TrackPopupMenu(pSubMenu->m_hMenu,<BR> 0,<BR> mouse.x,<BR> mouse.y,<BR> 0,<BR> m_nid.hWnd,<BR> NULL);<BR><BR> }
else // 双击事件:
执行菜单第一项<BR> ::SendMessage(m_nid.hWnd,
WM_COMMAND,
pSubMenu-><BR> GetMenuItemID(0),
0);<BR><BR> return 1; //
表示事件已被处理<BR>}<BR><BR> 以下以在VC++6.0中具体实现的程序为例。该程序将拥有以下功能:程序被执行<BR> 后,首先显示一对话框表示程序开始执行,然后该对话框消失。接着程序图标<BR> 被加入到系统托盘中,可以看到,该图标将是一动画图标。当鼠标在该系统托<BR> 盘上右击时,将弹出一菜单。如图所示(略)。其第一项为缺省项命令,单击<BR> 将显示应用程序。为简化编程,该应用程序只是显示一应用程序主窗口。而单击<BR> 菜单第二项将关闭机器,单击菜单第三项将结束本程序。当并且当用户双击时,<BR> CTrayIcon将执行菜单上的第一项:显示服务程序,这将击活(显示)TrayDemo<BR> (正常情况下,它是隐藏的)。而要终止TrayDemo,你得选择结束本程序。当你<BR> 执行File
Exit或关掉TrayDemo主窗口时,TrayDemo并没有真正的关掉,它只不过<BR> 隐藏起来了而已。TrayDemo
重载了Cmainframe::OnClose函数以执行该项功能。
<BR> 首先在VC++6.0中生成用应用程序向导生成一单文档工程TrayDemo,然后在工程中<BR> 加入以上的CTrayIcon类。
<BR><BR> 要使用CTrayIcon类,你首先得实例化一个CTrayIcon类对象,TrayDemo在视图中<BR> 完成此项工作。以下是对应代码:
<BR><BR>class CTrayDemoView : public CView {<BR>protected:
CTrayIcon m_trayIcon;
<BR> //
my tray
icon<BR> .<BR> .<BR> .<BR>};<BR><BR> 当你实例化一个CTrayIcon类对象之后,你必须分配给其一个ID号。该ID号是此图<BR> 标在其生命周期内使用的唯一一个ID号,即使在以后你改变了实际显示的图标。此<BR> ID号是当鼠标事件发生时你获得的ID。它可以不必是图标的资源ID;在TrayDemo<BR> 中,其值是IDR_TRAYICON,由CTrayDemoView构造函数所初始化。
<BR>CTrayDemoView::CTrayDemoView()
:<BR>m_trayIcon(IDR_TRAYICON){<BR> .<BR> .<BR> .<BR>}<BR><BR>要增加图标,可调用SetIcon重载函数之一<BR>m_trayIcon.SetIcon(IDI_MYICON);
//参数为资源ID<BR>m_trayIcon.SetIcon("myicon"); //参数为资源名<BR>m_trayIcon.SetIcon(hicon);
//参数为HICON句柄
<BR>m_trayIcon.SetStandardIcon(IDI_WINLOGO);<BR>//加入系统图标<BR><BR> 除了SetIcon(UINT
uID)函数需要一个同样拥有uID号的字符串资源作为提示字符串<BR> 以外,所有这些函数都有一个可选的指向提示字符串的LPCSTR参数。例如,在<BR> TRAYTEST中有以下行:
<BR>// (In
TrayDemoView.cpp)<BR>m_trayIcon.SetIcon(IDI_RED);<BR><BR> 该语句在增加图标的同时同样设定了提示字符串,因为TrayDemo有一个同样ID的字<BR> 符串:如果你想改变图标,只需再次调用其中的一个SetIcon函数,只不过需要不<BR> 同的ID或HICON。CTrayIcon类知道响应NIM_MODIFY消息而不是NIM_ADD消息。同样<BR> 的函数甚至可以去掉图标:
<BR>m_trayIcon.SetIcon(0);//removeicon<BR><BR> CtrayIcon类会将其解释为NIM_DELETE事件。这么多的代码和标志只用一个简单的<BR> 重载函数就予以完成,这是C++的伟大之处。
<BR> 如果要显示动画图标,只需设置一定时器,然后在定时器的响应事件中调用<BR> SetIcon成员函数就可以了。如:
<BR><BR>int CTrayDemoView::OnCreate(LPCREATESTRUCT
lpCreateStruct) <BR>{<BR>m_timerID =
this->SetTimer(99,200,NULL);<BR>…<BR>}<BR><BR>void
CTrayDemoView::OnTimer(UINT nIDEvent)
<BR>{<BR>uChangeIcon++;<BR>if(uChangeIcon-IDI_RED>2)<BR> uChangeIcon=IDI_RED;<BR>m_trayIcon.SetIcon(uChangeIcon);<BR>CView::OnTimer(nIDEvent);<BR>}<BR><BR> 在示例程序中,有3个图标,其ID为IDI_RED,IDI_YELLO,IDI_GREEN,且其ID值是相<BR> 连的,因而UINT型变量uChangeIcon用来依次轮换三个图标。这样程序执行以后,你<BR> 将会看到红、黄、绿三个交通指示灯依次闪烁。
<BR> 那么怎样处理托盘通知呢?
<BR><BR> 要处理托盘通知,需要在你设定图标之前调用CTrayIcon::SetNotificationWnd函<BR> 数,当然你必须已经创建了窗口。最适当的地方是在OnCreate函数中,在TrayDemo<BR> 中也是这样做的。用ClassWizard在CtrayDemoView类中加入WM_CREATE消息响应函<BR> 数OnCreate(),并加入以下代码:
<BR><BR>// Private message used for tray
notifications<BR>#define WM_MY_TRAY_NOTIFICATION
WM_USER+0<BR>int CTrayDemoView::OnCreate(LPCREATESTRUCT
lpCreateStruct)<BR> .<BR> .<BR> .<BR>m_trayIcon.SetNotificationWnd(this,WM_MY_TRAY_NOTIFICATION);<BR>m_trayIcon.SetIcon(IDI_RED);
<BR>return
0;<BR>}<BR><BR> 然后进行消息注册(REGISTER),一旦注册以后,你就可以用正常的消息映射方式<BR> 处理托盘通知。
<BR>BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
<BR>ON_MESSAGE(WM_MY_TRAY_NOTIFICATION,OnTrayNotification)<BR>//
(or
ON_REGISTERED_MESSAGE)<BR>END_MESSAGE_MAP()<BR><BR>当然不要忘了在TrayDemoView.h中加入以下语句:<BR>afx_msg
LRESULT OnTrayNotification(WPARAM wp, LPARAM
lp);<BR><BR> 当你的处理程序得到在托盘图标上的鼠标事件的控制以后,WPARAM参数是你在创建<BR> CTrayIcon类时定义的ID;LPARAM是鼠标事件(如,WM_LBUTTONDOWN)。当捕获到<BR> 通知后你可以做任何你想做的事情;记得最后要调用<BR> CTrayIcon::OnTrayNotification函数以完成一些缺省的处理。该虚函数完成前面<BR> 所提到的一些缸省的UI行为。特别的,它处理WM_LBUTTONDBLCLK和WM-RBUTTONUP事<BR> 件。CTrayIcon类寻找与图标拥有同样ID的菜单(如,IDR_TRAYICON)。如果拥有<BR> 该ID的菜单存在,CTrayIcon类将在用户右击图标的时候显示此菜单;而当用户双<BR> 击时,CTrayIcon将执行菜单上的第一个命令。
<BR><BR>LRESULT CTrayDemoView::OnTrayNotification(WPARAM wp,
LPARAM
lp)<BR>{ <BR> return
m_trayIcon.OnTrayNotification(wp,
lp);<BR>}<BR><BR> 只有两件事需要进一步解释。在显示菜单之前,CTrayIcon类使得第一项为缸省项,<BR> 因此它看起来是大写的。但怎样使得一个菜单项大写呢?使用函数
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -