在Windows *** 作系统中 任务栏的右边(托盘)会常驻几个图标 如输入法切换图标 音量控制图标等 此外我们还经常遇到具有托盘图标的软件 如金山词霸 实时监测功能的杀毒软件等 这些软件在后台运行 通常不占用太多的屏幕资源 只在通知栏上放一个小小的标志 必要时我们可以通过用鼠标点击图标对其进行选单 *** 作或激活其主窗口 有时我们自己编写的程序也希望有类似的效果 本文将详细地介绍用VC设计托盘图标程序的方法 一 NOTIFYICONDATA结构 NOTIFYICONDATA结构包含了系统用来处理托盘图标的信息 它包括选择的图标 回调消息 提示消息和图标对应的窗口等内容 其定义为 typedef struct—NOTIFYICONDATA { DWORD cbSize//以字节为单位的这个结构的大小 HWND hWnd//接收托盘图标通知消息的窗口句柄 UINT uID//应用程序定义的该图标的ID号 UINT uFlags//设置该图标的属性 UINT uCallbackMessage//应用程序定义的消息ID号 此消息传递给hWnd HICON hIcon//图标的句柄 char szTip[ ]//鼠标停留在图标上显示的提示信息 } NOTIFYICONDATA ?PNOTIFYICONDATA该结构中 成员uFlags可以是下列的组合或其中之一 NIF_ICON 设置成员hIcon有效 NIF_MESSAGE 设置成员uCallbackMessage有效 NIF_TIP 设置成员szTip有效 二 Shell_NotifyIcon函数 全局函数Shell_NotifyIcon()用于在托盘上增加 删除或修改图标 其原型为 WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( DWORD dwMessage PNOTIFYICONDATA pnid)Pnid是上面的NOTIFYICONDATA结构的指针 dwMessage是被传递的消息 可以是以下消息之一 NIM_ADD 增加图标 NIM_DELETE 删除图标 NIM_MODIFY 修改图标 三 托盘图标程序设计示例 首先我们用AppWizard创建一个不基于文档和视图结构的应用程序Tray 我们并不想在应用程序启动时显示主窗口 所以需要删除应用程序类CTrayApp中成员函数InitInstance()的以下两句代码 pFrame 〉ActivateFrame()pFrame 〉ShowWindow(SW_SHOW)在CMainFrame类中加入NOTIFYICONDATA结构的保护成员变量m_tnid 并在其OnCreate函数中return语句前加入生成托盘图标的代码 m_tnid cbSize=sizeof(NOTIFYICONDATA)m_tnid hWnd=this 〉m_hWndm_tnid uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIPm_tnid uCallbackMessage=MYWM_NOTIFYICON
//用户定义的回调消息 CString szToolTipszToolTip=_T( 托盘图标实例 )_tcscpy(m_tnid szTip szToolTip)m_tnid uID=IDR_MAINFRAMEHICON hIconhIcon=AfxGetApp() 〉LoadIcon(IDR_MAINFRAME)m_tnid hIcon=hIcon::Shell_NotifyIcon(NIM_ADD &&m_tnid)if(hIcon)::DestroyIcon(hIcon)返回消息的ID应在主框架类的头函数中定义 #define MYWM_NOTIFYICON WM_USER+ 为了处理图标返回消息 如鼠标左键双击 鼠标右键单击消息 我们重载WindowProc()函数 此外 我们还希望在主框架窗口最小化时图标不在任务栏的空白区出现 在此函数中同时作相应处理 LRESULT CMainFrame::WindowProc(UINT message WPARAM wParam LPARAM lParam) { switch(message){ case MYWM_NOTIFYICON: //如果是用户定义的消息 if(lParam==WM_LBUTTONDBLCLK){ //鼠标双击时主窗口出现 AfxGetApp() 〉m_pMainWnd 〉ShowWindow(SW_SHOW)} else if(lParam==WM_RBUTTONDOWN){ //鼠标右键单击d出选单 CMenu menumenu LoadMenu(IDR_RIGHT_MENU)//载入事先定义的选单 CMenu?pMenu=menu GetSubMenu( )CPoint posGetCursorPos(&&pos)pMenu 〉TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON pos x pos y AfxGetMainWnd())} breakcase WM_SYSMAND: //如果是系统消息 if(wParam= =SC_MINIMIZE){ //接收到最小化消息时主窗口隐藏 AfxGetApp() 〉m_pMainWnd 〉ShowWindow(SW_HIDE)return } break} return CFrameWnd::WindowProc(message wParam lParam)} 为使应用程序退出时图标消失 映射WM_DESTROY消息 在OnDestroy()函数中加入 ::Shell_NotifyIcon(NIM_DELETE &&m_tnid)至此 托盘图标程序的常规功能我们均已实现 我们还可以通过Shell_NotifyIcon()函数的调用实现不同状态下图标的改变 本程序在VC++ Windows / Professional下调试通过 lishixinzhi/Article/program/net/201311/11634程序(附后)用到了Shell_NotifyIcon、SendMessage、CallWindowProc、SetWindowLong等API函数,其中Shell_NotifyIcon是主要的函数,它用来添加、删除、更改系统托盘区(taskbar status area)的图标,所以我们先来看看这个函数的声明和参数:
使用API函数之前必须先在程序中声明如下:
Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
其中各参数的意义如下表:
参数: 意义
dwMessage 为消息设置值,它可以是以下的几个常数值:0、1、2
NIM_ADD = 0 加入图标到系统状态栏中
NIM_MODIFY = 1 修改系统状态栏中的图标
NIM_DELETE = 2 删除系统状态栏中的图标
LpData 用以传入NOTIFYICONDATA数据结构变量,其结构如下所示:
Type NOTIFYICONDATA
cbSize As Long需填入NOTIFYICONDATA数据结构的长度
HWnd As Long 设置成窗口的句柄
Uid As Long 为图标所设置的ID值
UFlags As Long设置uCallbackMessage,hIcon,szTip是否有效
UCallbackMessage As Long 消息编号
HIcon As Long 显示在状态栏上的图标
SzTip As String * 64 提示信息
End Type
返回值 Long,非零表示成功,零表示失败
在使用这个API函数之前我们应该先定义结构类型NOTIFYICONDATA:
Public Type NOTIFYICONDATA
cbSize As Long HWnd As Long
Uid As Long UFlags As Long
UCallbackMessage As Long
HIcon As Long
SzTip As String * 64
End Type
然后定义一个NOTIFYICONDATA的变量TheData来记录设置托盘图标的数据
Private TheData As NOTIFYICONDATA
这时我们就可以使用这个函数来设置系统托盘图标了,具体方法如下:
1、添加图标
With TheData
.Uid = 0
.HWnd = frm.HWnd 注释:frm.HWnd是程序主窗体的句柄
.cbSize = Len(TheData)
.HIcon = frm.Icon.Handle 注释:frm.Icon.Handle指向主窗体的图标
.UFlags = NIF_ICON
.UCallbackMessage = TRAY_CALLBACK
注释:作用是允许返回消息,在下一节中会有详细解释。
.UFlags = .UFlags Or NIF_MESSAGE
.cbSize = Len(TheData)
End With
Shell_NotifyIcon NIM_ADD, TheData
注释:根据前面定义NIM_ADD,设置为“添加模式”,然后添加
2、删去图标
With TheData
.UFlags = 0
End With
Shell_NotifyIcon NIM_DELETE, TheData
注释:根据前面定义NIM_DELETE,设置为“删除模式”
3、更改图标
With TheData
.HIcon = pic.Handle
注释:pic是图片狂PictureBox,存放图标文件
.UFlags = NIF_ICON
End With
Shell_NotifyIcon NIM_MODIFY, TheData
注释:根据前面定义NIM_MODIFY,设置为“更改模式”
4、为图标添加浮动提示信息
With TheData
.SzTip = tip &vbNullChar
注释:tip是字符串string,存储提示信息
.UFlags = NIF_TIP
注释:指明要对浮动提示进行设置
End With
Shell_NotifyIcon NIM_MODIFY, TheData
注释:根据前面定义NIM_MODIFY,设置为“修改模式”
通过以上几段代码我们就能根据自己需要添加、删除、更改系统托盘图标,并能添加系统图标上的浮动提示信息。但这时的托盘图标是孤立的,我们并不能利用它来控制应用程序的行为,怎么办呢?别急,请往下看……
如果你下载(源程序下载)并运行这个例程序,你会发现如果我们在托盘图标上点击鼠标右键,则会d出一个右键菜单。如果点击相应的菜单项,程序主窗体会随之变化,这样就可以控制程序的行为。而如果当主窗体处于最小化状态时,我们在托盘图标上点击左键,窗体会恢复到原来的大小。其实实现上述的功能都要依赖于WINDOWS *** 作系统的消息机制,要完全弄懂这个机制挺不容易的,但是我们可以按下述文字来理解它。
把WINDOWS *** 作系统看作人的大脑,它接收、处理、并发送各种各样的信息给我们的各个器官(当然是比喻各个应用程序了),也就是说它是消息的中枢。而每个应用程序(甚至每一个按钮、标签、窗体等等统称为窗口)在运行时都会被分配一个窗口过程WINDOWPROC,由这个窗口过程来接收和处理 *** 作系统发来的消息(实际上存在一个消息队列),通常情况下这个窗口过程是由 *** 作系统指定的,它会自动的响应并处理一些WINDOWS消息(如窗体移动、最大化、最小化、错误信息等)。好,到这我们先停一下,提出一个疑问,这些消息能否由我们自己写程序来处理呢?答案是肯定的,不过还得借助API函数的威力了,怎么用?我们还是先看看这些API函数的定义和参数吧。
程序中用到了SendMessage、CallWindowProc、SetWindowLong等API函数,其中SendMessage函数的作用是将一条消息发给某个窗口;CallWindowProc函数用来发送消息到一个窗口过程;而使用SetWindowLong函数来为窗口结构中为指定的窗口设置属性。使用API函数之前必须先在程序中声明如下:
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal HWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal HWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal HWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
其中各参数的意义如下表:
CallWindowProc函数
参数 意义
lpPrevWndFunc Long,原来的窗口过程地址
HWnd Long,窗口句柄
Msg Long,发送的消息
wParam Long,消息类型,参考wParam参数表
lParam Long,依据wParam参数的不同而不同
返回值 Long,依据发送的消息不同而变化
SetWindowLong函数 :
参数 意义
hwnd Long,欲为其取得信息的窗口的句柄
nIndex Long,请参考GetWindowLong函数的nIndex参数的说明
dwNewLong Long,由nIndex指定的窗口信息的新值
返回值 Long,指定数据的前一个值
SendMessage函数 :
参数 意义
hwnd Long,要接收消息的那个窗口的句柄
wMsg Long,消息的标识符
wParam Long,具体取决于消息
lParam Any,具体取决于消息
返回值 Long,由具体的消息决定
我们要自己写程序来处理消息,必须先更改窗口的属性,从原来由默认的窗口过程来处理消息变成由我们自己写的消息处理过程来处理消息。方法是使用SetWindowLong函数来取得默认窗口过程的地址,然后转向为我们自己写的窗口过程的地址,具体的实现方法如下代码:
注释:GWL_WNDPROC获得该窗口的窗口过程的地址,AddressOf是取址函数,NewWindowProc是我们写的过程
OldWindowProc = SetWindowLong(frm.HWnd, GWL_WNDPROC, AddressOf
NewWindowProc)
然后在NewWindowProc函数中写入如下代码,需要注意的是下面代码中红色的TRAY_CALLBACK是由托盘区图标传来的消息,要让托盘图标传回消息,必须在添加托盘图标时指定:
Public Function NewWindowProc(ByVal HWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
注释:如果用户点击了托盘中的图标,则进行判断是点击了左键还是右键
If Msg = TRAY_CALLBACK Then
注释:如果点击了左键
If lParam = WM_LBUTTONUP Then
注释:而这时窗体的状态是最小化时
If TheForm.WindowState = vbMinimized Then _
注释:恢复到最小化前的窗体状态
TheForm.WindowState = TheForm.LastState
TheForm.SetFocus
Exit Function
End If
End If
注释:如果点击了右键
If lParam = WM_RBUTTONUP Then
注释:则d出右键菜单
TheForm.PopupMenu TheMenu
Exit Function
End If
End If
注释:如果是其他类型的消息则传递给原有默认的窗口函数
NewWindowProc = CallWindowProc(OldWindowProc, HWnd, Msg, wParam, lParam)
End Function
这样我们就取得并处理了来自托盘图标的消息,现在的问题是在鼠标右键菜单d出后,怎么控制程序主窗体的状态,这时我们需要用到SendMessage函数来向主窗体发送最大化、最小化、关闭、移动等消息,具体的代码实现如下,其中HWnd是主窗体的句柄,WM_SYSCOMMAND表示发送的是系统控制类的消息,SC_MOVE、SC_SIZE、SC_RESTORE便是要发送的消息了:
注释:托盘图标右键菜单上的“移动”项被点击时
Private Sub mnuTrayMove_Click()
SendMessage HWnd, WM_SYSCOMMAND, SC_MOVE, 0&
End Sub
注释:托盘图标右键菜单上的“恢复”项被点击时
Private Sub mnuTrayRestore_Click()
SendMessage HWnd, WM_SYSCOMMAND, SC_RESTORE, 0&
End Sub
注释:托盘图标右键菜单上的“退出”项被点击时
Private Sub mnuTraySize_Click()
SendMessage HWnd, WM_SYSCOMMAND, SC_SIZE, 0&
End Sub
最后要提醒你,在程序退出时一定要把窗口过程的地址恢复为默认值,同时把托盘图标移去哦。
为了学习方便,以下提供了源代码:
注释:---------------------------------------------
注释: 使用系统托盘程序演示
注释:---------------------------------------------
注释:程序说明:
注释: 这是一个比较完整的使用系统托盘的程序实例,包括
注释:了:添加托盘图标,删除托盘图标,动态改变托盘图标,
注释:为托盘图标添加浮动提示信息,实现托盘图标的鼠标右键
注释:菜单等内容。
注释:-------名称-------------------作用------------
注释: Form1 主窗体
注释: mnuFile,mnuFileExit 文件菜单,菜单项
注释: mnuTray,mnuTrayClose... 托盘区右键菜单,菜单项
注释:---------------------------------------------
Option Explicit
注释:LastState变量的作用是标示主窗体原有状态
Public LastState As Integer
注释:【VB声明】
注释: Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
注释:【说明】
注释: 调用一个窗口的窗口函数,将一条消息发给那个窗口。除非消息处理完毕,否则该函数不会返回。SendMessageBynum,
注释: SendMessageByString是该函数的“类型安全”声明形式
注释:【返回值】
注释: Long,由具体的消息决定
注释:【参数表】
注释: hwnd ----------- Long,要接收消息的那个窗口的句柄
注释: wMsg ----------- Long,消息的标识符
注释: wParam --------- Long,具体取决于消息
注释: lParam --------- Any,具体取决于消息
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal HWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
注释:表示发送的是系统命令
Private Const WM_SYSCOMMAND = &H112
Private Const SC_MOVE = &HF010&
Private Const SC_RESTORE = &HF120&
Private Const SC_SIZE = &HF000&
注释:当主窗体加载时
Private Sub Form_Load()
注释:窗体的WindowState属性,返回或设置一个值,该值用来指定在运行时窗体窗口的可视状态
注释:vbNormal 0 (缺省值)正常 。
注释:VbMinimized 1 最小化(最小化为一个图标)
注释:VbMaximized 2 最大化(扩大到最大尺寸)
If WindowState = vbMinimized Then
LastState = vbNormal
Else
LastState = WindowState
End If
注释:将图标添加到托盘的函数,参见模块中的解释
注释:注意了这是从主程序到模块的入口,本例中并没有直接调用Shell_NotifyIcon函数
AddToTray Me, mnuTray
SetTrayTip "托盘图标演示,点击右键d出菜单"
End Sub
注释:在主窗体Form1大小改变时,相应改变右键菜单mnuTray的菜单项的可用属性Enabled
Private Sub Form_Resize()
Select Case WindowState
注释:如果窗体最小化了,把菜单项“最大化”“恢复”设为可用,
注释:而把“最小化”“移动”“大小”三项设为不可用.
注释:如果这时在托盘图标上点击鼠标右键,会发现不可用项变为灰色
Case vbMinimized
mnuTrayMaximize.Enabled = True
mnuTrayMinimize.Enabled = False
mnuTrayMove.Enabled = False
mnuTrayRestore.Enabled = True
mnuTraySize.Enabled = False
注释:窗体最大化时
Case vbMaximized
mnuTrayMaximize.Enabled = False
mnuTrayMinimize.Enabled = True
mnuTrayMove.Enabled = False
mnuTrayRestore.Enabled = True
mnuTraySize.Enabled = False
注释:一般状态下
Case vbNormal
mnuTrayMaximize.Enabled = True
mnuTrayMinimize.Enabled = True
mnuTrayMove.Enabled = True
mnuTrayRestore.Enabled = False
mnuTraySize.Enabled = True
End Select
If WindowState <>vbMinimized Then LastState = WindowState
End Sub
注释:保证在程序退出时删除托盘图标
Private Sub Form_Unload(Cancel As Integer)
RemoveFromTray
End Sub
注释:“文件”菜单的“退出”项被点击时
Private Sub mnuFileExit_Click()
Unload Me
End Sub
注释:托盘图标右键菜单上的“退出”项被点击时
Private Sub mnuTrayClose_Click()
Unload Me
End Sub
注释:托盘图标右键菜单上的“最大化”项被点击时
Private Sub mnuTrayMaximize_Click()
WindowState = vbMaximized
End Sub
注释:托盘图标右键菜单上的“最小化”项被点击时
Private Sub mnuTrayMinimize_Click()
WindowState = vbMinimized
End Sub
注释:托盘图标右键菜单上的“移动”项被点击时
Private Sub mnuTrayMove_Click()
SendMessage HWnd, WM_SYSCOMMAND, _
SC_MOVE, 0&
End Sub
注释:托盘图标右键菜单上的“恢复”项被点击时
Private Sub mnuTrayRestore_Click()
SendMessage HWnd, WM_SYSCOMMAND, _
SC_RESTORE, 0&
End Sub
注释:托盘图标右键菜单上的“退出”项被点击时
Private Sub mnuTraySize_Click()
SendMessage HWnd, WM_SYSCOMMAND, _
SC_SIZE, 0&
End Sub
注释:-----------------------------------------
注释:以下为模块中的代码:
注释:-----------------------------------------
Option Explicit
Public OldWindowProc As Long
Public TheForm As Form
Public TheMenu As Menu
注释:【VB声明】
注释:Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal HWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
注释:【说明】
注释: 此函数发送消息到一个窗口过程
注释:【返回值】
注释: Long,依据发送的消息不同而变化
注释:【参数表】
注释: lpPrevWndFunc----- Long,原来的窗口过程地址
注释: HWnd-------------- Long,窗口句柄
注释: Msg -------------- Long,发送的消息
注释: wParam ----------- Long,消息类型,参考wParam参数表
注释: lParam ----------- Long,依据wParam参数的不同而不同
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal HWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
注释:【VB声明】
注释: Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
注释:【说明】
注释: 在窗口结构中为指定的窗口设置信息
注释:【返回值】
注释: Long,指定数据的前一个值
注释:【参数表】
注释: hwnd ----------- Long,欲为其取得信息的窗口的句柄
注释: nIndex --------- Long,请参考GetWindowLong函数的nIndex参数的说明
注释: dwNewLong ------ Long,由nIndex指定的窗口信息的新值
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal HWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
注释:【VB声明】
注释:Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
注释:【说明】
注释:【参数表】
注释:参数dwMessage ---- 为消息设置值,它可以是以下的几个常数值:0、1、2
注释:NIM_ADD = 0 加入图标到系统状态栏中
注释:NIM_MODIFY = 1 修改系统状态栏中的图标
注释:NIM_DELETE = 2 删除系统状态栏中的图标
注释:参数LpData ---- 用以传入NOTIFYICONDATA数据结构变量,我们也需要在"模块"中定义其结构如下:
注释:Type NOTIFYICONDATA
注释: cbSize As Long 需填入NOTIFYICONDATA数据结构的长度
注释: HWnd As Long 设置成窗口的句柄
注释: Uid As Long 为图标所设置的ID值
注释: UFlags As Long 用来设置以下三个参数uCallbackMessage、hIcon、szTip是否有效
注释: UCallbackMessage As Long 消息编号
注释: HIcon As Long 显示在状态栏上的图标
注释: SzTip As String * 64 提示信息
注释:End Type
注释:---- 其中参数uCallbackMessage、hIcon、szTip也应在模块中声明为以下的常量:
注释:Public Const NIF_MESSAGE = 1
注释:Public Const NIF_ICON = 2
注释:Public Const NIF_TIP = 4
Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
Public Const WM_USER = &H400
Public Const WM_LBUTTONUP = &H202
Public Const WM_MBUTTONUP = &H208
Public Const WM_RBUTTONUP = &H205
Public Const TRAY_CALLBACK = (WM_USER + 1001&)
Public Const GWL_WNDPROC = (-4)
Public Const GWL_USERDATA = (-21)
Public Const NIF_ICON = &H2
Public Const NIF_TIP = &H4
Public Const NIM_ADD = &H0
Public Const NIF_MESSAGE = &H1
Public Const NIM_MODIFY = &H1
Public Const NIM_DELETE = &H2
注释:记录 设置托盘图标的数据 的数据类型NOTIFYICONDATA
Public Type NOTIFYICONDATA
cbSize As Long
HWnd As Long
Uid As Long
UFlags As Long
UCallbackMessage As Long
HIcon As Long
SzTip As String * 64
End Type
注释:TheData变量记录设置托盘图标的数据
Private TheData As NOTIFYICONDATA
注释: *********************************************
注释: 新的窗口过程--主程序中采用SetWindowLong函数改变了窗口函数的地址,消息转向由NewWindowProc处理
注释: *********************************************
Public Function NewWindowProc(ByVal HWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
注释:如果用户点击了托盘中的图标,则进行判断是点击了左键还是右键
If Msg = TRAY_CALLBACK Then
注释:如果点击了左键
If lParam = WM_LBUTTONUP Then
注释:而这时窗体的状态是最小化时
If TheForm.WindowState = vbMinimized Then _
注释:恢复到最小化前的窗体状态
TheForm.WindowState = TheForm.LastState
TheForm.SetFocus
Exit Function
End If
End If
注释:如果点击了右键
If lParam = WM_RBUTTONUP Then
注释:则d出右键菜单
TheForm.PopupMenu TheMenu
Exit Function
End If
End If
注释:如果是其他类型的消息则传递给原有默认的窗口函数
NewWindowProc = CallWindowProc(OldWindowProc, HWnd, Msg, wParam, lParam)
End Function
注释: *********************************************
注释: 把主窗体的图标(Form1.icon属性可改变)添加到托盘中
注释: *********************************************
Public Sub AddToTray(frm As Form, mnu As Menu)
注释:保存当前窗体和菜单信息
Set TheForm = frm
Set TheMenu = mnu
注释:GWL_WNDPROC获得该窗口的窗口函数的地址
OldWindowProc = SetWindowLong(frm.HWnd, GWL_WNDPROC, AddressOf NewWindowProc)
注释:知识点滴:HWnd属性
注释:返回窗体或控件的句柄。语法: object.HWnd
注释:说明:Microsoft Windows 运行环境,通过给应用程序中的每个窗体和控件
注释:分配一个句柄(或 hWnd)来标识它们。hWnd 属性用于Windows API调用。
注释:将主窗体图标添加在托盘中
With TheData
.Uid = 0 注释:忘了吗?参考一下前面内容,Uid图标的序号,做动画图标有用
.HWnd = frm.HWnd
.cbSize = Len(TheData)
.HIcon = frm.Icon.Handle
.UFlags = NIF_ICON 注释:指明要对图标进行设置
.UCallbackMessage = TRAY_CALLBACK
.UFlags = .UFlags Or NIF_MESSAGE 注释:指明要设置图标或返回信息给主窗体,此句不能省去
.cbSize = Len(TheData) 注释:为什么呢?我们需要在添加图标的同时,让其返回信息
End With 注释:给主窗体,Or的意思是同时进行设置和返回消息
Shell_NotifyIcon NIM_ADD, TheData 注释:根据前面定义NIM_ADD,设置为“添加模式”
End Sub
注释: *********************************************
注释: 删除系统托盘中的图标
注释: *********************************************
Public Sub RemoveFromTray()
注释:删除托盘中的图标
With TheData
.UFlags = 0
End With
Shell_NotifyIcon NIM_DELETE, TheData 注释:根据前面定义NIM_DELETE,设置为“删除模式”
注释:恢复原有的设置
SetWindowLong TheForm.HWnd, GWL_WNDPROC, OldWindowProc
End Sub
注释: *********************************************
注释: 为托盘中的图标加上浮动提示(也就是鼠标移上去时出现的提示字条)
注释: *********************************************
Public Sub SetTrayTip(tip As String)
With TheData
.SzTip = tip &vbNullChar
.UFlags = NIF_TIP 注释:指明要对浮动提示进行设置
End With
Shell_NotifyIcon NIM_MODIFY, TheData 注释:根据前面定义NIM_MODIFY,设置为“修改模式”
End Sub
注释: *********************************************
注释: 设置托盘的图标(在本例中没有用到,如果要动态改变托盘内显示的图标,它非常有用)
注释: 例如:1、显示动画图标(方法你一定猜到了,对!使用Timer控件,不断调用此过程,注意把动画放在pic数组中)
注释: 2、程序处于不同状态时,显示不同的图标,方法是类似的
注释: 有兴趣的话试一试吧。
注释: *********************************************
Public Sub SetTrayIcon(pic As Picture)
注释:判断一下pic中存放的是不是图标
If pic.Type <>vbPicTypeIcon Then Exit Sub
注释:更换图标为pic中存放的图标
With TheData
.HIcon = pic.Handle
.UFlags = NIF_ICON
End With
Shell_NotifyIcon NIM_MODIFY, TheData
End Sub
Windows 95以及后来的Windows版本允许你将程序图标放入系统托盘。所谓系统托盘,通常指的是屏幕右下方显示时间,音量等图标的那个区域。这个区域主要用于显示状态信息或者当你运行的程序不可见时,允许你方便地访问程序的主要特性。这个区域还可以用于显示小程序的图标,以便用户容易访问主程序,或者在预定的时间加载主程序。有些系统托盘图标可以变化用以指示程序状态,例如,浏览器的系统托盘图标当modem接收和发送数据时显示的是不同的图标。把鼠标移到托盘图标上停留一下常常会显示一个提示,根据程序的状态,它可能也会变化。在托盘图标上单击鼠标右键常常显示一个程序菜单,而双击鼠标左键常常可以启动主窗口或应用程序。
访问系统托盘的方法是通过Shell_NotifyIcon函数和NOTIFYICONDATA结构实现的。
typedef struct _NOTIFYICONDATA {
DWORD cbSize
HWND hWnd
UINT uID
UINT uFlags
UINT uCallbackMessage
HICON hIcon
TCHAR szTip[64]
DWORD dwState //Version 5.0
DWORD dwStateMask //Version 5.0
TCHAR szInfo[256] //Version 5.0
UINT uTimeout //Version 5.0
TCHAR szInfoTitle[64] //Version 5.0
DWORD dwInfoFlags //Version 5.0
} NOTIFYICONDATA, *PNOTIFYICONDATA
为了要在系统托盘中显示图标,用NIM_ADD标志调用Shell_NotifyIcon函数。
#define ID_TASKBARICON 100
#define WM_ICONNOTIFY (WM_USER + 101)
NOTIFYICONDATA nid
// 初始化系统托盘图标
m_tnid.cbSize=sizeof(NOTIFYICONDATA)
m_tnid.hWnd=this->m_hWnd
m_tnid.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP
m_tnid.uCallbackMessage=MYWM_NOTIFYICON
CString szToolTip
szToolTip=_T("托盘实例")
_tcscpy(m_tnid.szTip,szToolTip)
m_tnid.uID=IDR_MAINFRAME
m_tnid.hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME)
::Shell_NotifyIcon(NIM_ADD,&m_tnid)
cbSize成员是结构的大小(使用它主要是为了支持将来这个结构大小增加)。
hWnd是窗口句柄。当图标发生某事件时(如单击、双击等),Windows将向窗口发送uCallbackMessage成员指定的消息。uID成员指定与图标关联的ID。它不是很重要,除非你需要显示并跟踪几个图标。
uFlag成员告诉Windows应该读取哪个成员。当添加一个图标时,应该包含这个结构的大多数成员。当更新图标时,如只是需要改变图标时,你只要设置相应
的标志就可以了。
hIcon成员是你想显示的图标。 最后,szTip成员是提示文本。设置好这些结构成员后,调用Shell_NotifyIcon函数。
当与图标关联的事件发生时,Windows将发送uCallbackMessage成员指定的消息。IParam包含发送的消息。当获得WM_LBUTTONDBLCLK消息时显示主窗口 在这里我们可以定义一个WM_MYNOTIFYICON
#define WM_MYNOTIFYICON WM_USER+101或者启动主程序。当获得WM_RBUTTONUP消息时显示菜单。
注意:如果在系统托盘中单击鼠标右键,有时会有一个d出式(上下文菜单)菜单显示/消失的怪现象,可以参考下列代码加以解决。
switch(message)
{
case MYWM_NOTIFYICON:
if(lParam==WM_LBUTTONDBLCLK)
{
AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW)
CenterWindow()
}
else if(lParam==WM_RBUTTONDOWN)
{
CMenu menu
menu.LoadMenuW(IDM_RIGHT_MENU)
CMenu *pMenu
pMenu=menu.GetSubMenu(0)
POINT point
GetCursorPos(&point)
pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,AfxGetMainWnd())
}
break
case WM_SYSCOMMAND:
if(wParam==SC_MINIMIZE||wParam==SC_CLOSE)
{
AfxGetApp()->m_pMainWnd->ShowWindow(SW_HIDE)
return 0//请问这里为什么要加个return 0 呢???
}
break
} 不论什么时候,你都可以用 NIM_MODIFY 调用 Shell_NotifyIcon。程序终止之前,用 NIM_DELETE 调用 Shell_NotifyIcon从托盘中清除图标。
Shell_NotifyIcon(NIM_DELETE, &nid)
另外打开程序时直接最小托盘
CMyEyeProtectApp::InitInstance()函数中
m_pMainWnd->ShowWindow(SW_HIDE)
这样就可以在开始的时候直接进入托盘
另外在程序开始之前出现一个几秒钟的启动画面
CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)函数中
CSplashDlg *dlg=new CSplashDlg(this)
dlg->Create(CSplashDlg::IDD,this)
dlg->ShowWindow(SW_SHOW)
dlg->CenterWindow(this)
dlg->UpdateWindow()
Sleep(2000)
dlg->DestroyWindow()
把那对话框的属性贴上你想显示的图片,然后去掉边框,再按上面方法处理就可以了
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)