首 页 网络编程
网页制作 图形图象 操作系统 冲浪宝典
软件教学 认证考试

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 软件教学-> 办公软件
windows通知栏图标高级编程概述_delphi教程
作者:网友供稿 点击:0
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 
任务栏(Taskbar)是微软公司在Windows 95中引入的一种特殊的桌面工具条,它为用户快速访问计算机资源提供了极大的方便,而状态栏(以下称通知栏)无疑是任务栏上较为特殊的一个窗口。编程人员可以调用API函数Shell_NotifyIcon向通知栏发送消息来添加、删除或修改图标,当在图标上发生鼠标或键盘事件时,系统会向应用程序发送编程时预先定义的消息,通知栏处理回调函数就会被自动调用以做出相应的处理。实现上述功能的相关文章俯仰即拾,此处不再赘述。本文将讨论通知栏编程中几个较为深入的问题及其在Delphi中的实现方法。
l         新版Windows操作系统引入的卡通风格的气泡提示(Balloon ToolTips)的实现及相关事件通知
l         外壳Explorer.exe崩溃而重启后通知栏图标的自动恢复
l         为通知栏图标快捷菜单选择适当的弹出时机
l         鼠标双击事件发生时单击事件的避免
 

1 气泡提示(Balloon ToolTips)的实现

1.1 显示气泡提示

我们知道,Shell_NotifyIcon函数需要传入指向某个特定结构的指针,系统根据该结构所包含的信息来决定是向通知栏添加、删除或修改图标。该结构的传统定义如下所示:
 
_NOTIFYICONDATAA = record
 
  cbSize: DWORD;
//该结构的大小
  Wnd: HWND;
//接收通知消息的窗口句柄
  uID: UINT;
//图标标识(可以添加多个图标)
  uFlags: UINT;
//指明该结构中哪些字段的值有效
  uCallbackMessage: UINT;
//程序定义的接收通知的回调消息
  hIcon: HICON;
//图标句柄
  szTip: array [0..63] of AnsiChar;
//鼠标经过图标时显示的提示信息
end;
 
 
气泡提示(Balloon ToolTips)(如图1)是装有Internet Explorer 5及以上版本浏览器的操作系统(Windows Me/2000/XP,不包括Windows9x)中引入的通知栏图标的新行为,同时系统也定义了新版本的NOTIFYICONDATA结构,用于支持气泡提示。本文中将新结构取名为TNotifyIconData50,其Object Pascal定义及相关字段意义说明如下所示:
 
TNotifyIconData50 = record
 
前7个字段定义与_NOTIFYICONDATAA基本相同
  uFlags: UINT;
//uFlags字段增加了如下常数定义
NIF_STATE:dwState、dwStateMask字段有效
NIF_INFO:szInfo、uTimeout、szInfoTitle、
   dwInfoFlags字段有效
NIF_GUID:保留值
  dwState: DWORD;
//图标状态
NIS_HIDDEN:图标是隐藏的
NIS_SHAREDICON:图标是共享的
  dwStateMask: DWORD;
//指明dwState的哪些位可以被读取
如:设置为NIS_HIDDEN则表示图标的隐藏状态可以被读取
  szInfo: array[0..255] of
    AnsiChar;
//保存气泡提示字符串
  uTimeout: UINT;
//气泡提示显示的持续时间
系统默认设置最短10秒,最长30秒
  szInfoTitle: array[0..63]
    of AnsiChar;
//保存气泡提示标题
  dwInfoFlags: DWORD;
//指明是否在气泡提示上显示图标
NIIF_ERROR:“错误”图标
NIIF_INFO:“信息”图标
NIIF_NONE:不显示图标
NIIF_WARNING:“警告”图标
NIIF_ICON_MASK:保留值
NIIF_NOSOUND:不播放音效
end;
 
 
以下代码演示了在Delphi中如何实现气泡提示。
//{-------------------常数声明----------------------
Const
  NIIF_NONE        = $00000000;
  NIIF_INFO         = $00000001;
  NIIF_WARNING      = $00000002;
  NIIF_ERROR            = $00000003;
//--------------------------------------------------------------------------}
 
//{------------------类型声明--------------------
Type
  TBalloonTimeout = 10..30;         //气泡提示持续时间,单位为秒
 
  TBalloonIconType = (                 //气泡提示信息图标控制
    bitNone,                        //不显示图标
    bitInfo,                            //“信息”图标(蓝色)
    bitWarning,                         //“警告”图标(黄色)
    bitError);                      //“错误”图标(红色)
……
end;
//-----------------------------------------------}
 
//{---------填写公共结构----------------------------
procedure TEoCSysTray.FillDataStructure;
begin
  with FIconData do
  begin
    cbSize := SizeOf(TNotifyIconData50);
    wnd := FWindowHandle;
    uID := 0;                    
    uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
//uCallbackMessage、hIcon、szTip三个字段有效
    hIcon := FIcon.Handle;
    StrPCopy(szTip, FHint);
    uCallbackMessage := WM_SYSTRAY;
  end;
end; //end of procedure FillDataStructure
//--------------------------------------------------}
 
//{---------显示气泡提示信息----------------------
function TEoCSysTray.Balloon(Title, Text: string;
  IconType: TBalloonIconType; Timeout: TBalloonTimeout): Boolean;
const
  aBalloonIconTypes : array[TBalloonIconType] of Byte =
    (NIIF_NONE, NIIF_INFO, NIIF_WARNING, NIIF_ERROR);
begin
  if fActive then                          //若通知栏图标处于显示状态
  begin                                 //删除原先的气泡提示
    FillDataStructure;
    with FIconData do
    begin
      uFlags := uFlags or NIF_INFO;     //设置与气泡提示相关的字段有效
      StrPCopy(szInfo, );                 //设置提示信息为空,删除气泡提示
    end;
    Shell_NotifyIcon(NIM_MODIFY, @FIconData);
 
//以下显示新的气泡提示
    FillDataStructure;
    with FIconData do
    begin
      uFlags := uFlags or NIF_INFO;
      StrPCopy(szInfo, Text);
      uTimeout := Timeout;
      StrPCopy(szInfoTitle, Title);
      dwInfoFlags := aBalloonIconTypes[IconType];
    end {with};
    Result := Shell_NotifyIcon(NIM_MODIFY, @FIconData)
  end
  else
    result := True;
end; //end of procedure Balloon
//---------------------------------------------------}
 

1.2 气泡提示的事件通知

由于新风格提示的引入,通知栏图标的消息通知也相应增加,如果通知栏图标实现了气泡提示,那么当用户将鼠标指针移动到通知栏图标上时,Windows外壳会向通知栏应用程序送出如下四个消息中的一个或多个。
 
NIN_BALLOONSHOW
当气泡提示显示后外壳发送此消息
NIN_BALLOONTIMEOUT
当气泡提示由于超时而消失时外壳发送此消息
NIN_BALLOONHIDE
当气泡提示消失时(比如通知栏图标被删除)外壳发送此消息,但气泡提示由于超时而消失不会产生此消息
NIN_BALLOONUSERCLICK
当用户点击鼠标时(点击气泡提示和通知栏图标均可)外壳发送此消息
 
在Delphi强大的消息封装机制支持下,可以方便地将上述四个消息封装为四个事件供开发人员使用。简单来说就是在控件中一个隐藏窗口(创建隐藏窗口的方法可查阅相关文章,此处略过)的窗口消息处理过程中接收这四个消息并分别映射到四个事件,示范代码如下:
 
procedure TEoCSysTray.WndProc(var Msg: TMessage);
begin
……
  case Msg.LParam of
    WM_LBUTTONDOWN:
……
    WM_RBUTTONDBLCLk:
……
  else if Msg.lParam = NIN_BALLOONSHOW then   //气泡提示显示后
  begin
    if Assigned(FOnBalloonShow) then
      FOnBalloonShow(Self)
  end
  else if Msg.lParam = NIN_BALLOONHIDE then   //气泡提示由于超时而消失
  begin
    if Assigned(FOnBalloonHide) then
      FOnBalloonHide(Self)
  end
  else if Msg.lParam = NIN_BALLOONTIMEOUT then    //气泡提示消失
  begin
    if Assigned(FOnBalloonTimeOut) then
      FOnBalloonTimeOut(Self)
  end
  else if Msg.lParam = NIN_BALLOONUSERCLICK then  //用户点击鼠标
  begin
    if Assigned(FOnBalloonClick) then
      FOnBalloonClick(Self)
  end
  else
    Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
  end;
end; //end of procedure WndProc
 
 

2 Windows发生错误导致外壳Explorer重启时图标的重建

相信很多Windows用户都碰到过这种情况:运行某个程序时出现意外错误,导致外壳程序Explorer.exe崩溃而发生重启(即Explorer.exe被关闭后重新运行),任务栏也在消失后重新生成,但应用程序在通知栏添加的图标消失了,虽然这些程序仍在运行,但再也无法通过通知栏图标与用户交互。为避免这种情况出现,Windows提供了相应的机制。
在安装了Internet Explorer 4.0及以上版本的Windows操作系统中,当任务栏建立后,外壳会向所有顶层的应用程序发出通知消息,该消息是外壳以字符串“TaskbarCreated”为参数向系统注册获得的,应用程序窗口接收到该消息后就应该重新添加的通知栏图标。
在Delphi中实现过程如下:
 
initialization
  MsgTaskbarRestart := RegisterWindowMessage(‘TaskbarCreated’);
 
1.        重载主窗口的消息处理过程,拦截任务栏重建消息,进行重新添加图标的操作。
 
procedure TMainForm.WndProc(var Message: TMessage);
begin
  ……
  if Message.Msg = MsgTaskbarRestart then
  begin
    TrayIcon.Active := False;                  //删除通知栏图标
    TrayIcon.Active := True;                      //添加通知栏图标
  end;
  ……
  inherited WndProc(Message);
end; //end of WndProc
 
值得一提的是,如果将自动恢复的功能封装为控件,将以后的开发带来方便。但由于外壳只向所有顶层的应用程序发送通知,封装起来有一定的困难。因为通知栏图标的回调函数只能接收WM_XBUTTONDOWN、WM_XBUTTONUP等有限的几个消息,并不能接收所有的窗口消息。
解决的方法是使用SetWindowLong函数。通过向它传入GWL_WNDPROC参数,可以改变一个窗口的窗口过程。只需在创建控件时将应用程序窗口的窗口过程指针保存起来,并指向为控件中的某个新的窗口处理过程,在控件中就能够响应所有的窗口消息了(包括任务栏重建的消息);当控件销毁的时候再将保存的原始窗口过程指针恢复即可,此处不再赘述。
 
 

3 与通知栏图标关联的快捷菜单弹出的时机

本节将讨论编写通知栏应用程序时应该注意的一个问题,即快捷菜单弹出的时机问题。Windows为通知栏图标提供了几个鼠标消息(事件),那么我们应该将弹出快捷菜单的代码写在哪个事件中呢?先别急于回答“放在MouseDown事件中”,事实上,这个看似简单的问题,其中却小有讲究。许多软件(有的甚至号称专业级软件)也都或多或少忽视了这个问题。
首先需要明确一个软件设计中通用的原则,即:应当给用户一个机会以确认是否执行他选择的操作。这在软件设计中有很多例子。大的方面,最普遍的,如用户选择了删除文件,应弹出窗口予以确认。小的方面,如Windows中对鼠标的常规处理,也有一个确认的动作。一般来说,Windows中的程序对于鼠标事件的响应都是这样:在用户松开鼠标后才认为他确认了点击操作。以按钮(Button)为例,对于Windows的标准按钮,用户都可以在按下鼠标后而未松开鼠标前把鼠标移动到按钮区域以外来取消这次单击操作。再如Windows中窗口系统菜单的弹出,当用户在窗口标题栏上按下鼠标右键后,可以把鼠标移动到标题栏以外再松开,这样系统菜单就不会弹出,即等价于用户取消了该次操作。
遵照这个原则,通知栏快捷菜单的弹出显然应该在用户松开鼠标按键后,即WM_XBUTTONUP消息到来时才发生,以保证用户能够在松开鼠标之前取消其弹出,而不应简单的把弹出菜单的代码放在WM_XBUTTONDOWN的消息响应中。纵观Windows操作系统附带的程序,皆是如此。
 
 

4 鼠标双击事件发生时单击事件的避免

编写过通知栏应用程序的朋友大概都碰到过这样的情况:如果编写了响应鼠标单击(WM_XBUTTONUP)与双击(WM_XBUTTONDBLCLK)的代码,那么在用户双击鼠标时单击事件也会发生。而在实际应用中通常希望单击与双击是相互独立的两个操作,它们之间不应该互相影响。对于这一问题,有些软件采用“鸵鸟战术”,不响应单击事件(即对WM_XBUTTONUP消息不作响应),只响应双击事件,这未尝不是一种解决办法,但浪费了单击事件,算不得好。通过下面的分析,我们将会看到一个较为令人满意的解决方法。
 

4.1 原理分析

在Windows中并没有定义表示鼠标单击的消息,单击事件在Delphi等可视化编程语言中定义为鼠标按下后松开,因而单击事件一般在WM_XBUTTONUP中触发。而双击事件则不同,它在Windows中有明确的定义,当用户双击任意一个鼠标按键时,实际上按如下顺序Windows送出了四次消息:WM_XBUTTONDOWN、WM_XBUTTONUP、WM_XBUTTONDBLCLK、WM_XBUTTONUP。显然,如果响应WM_XBUTTONUP消息而触发了单击事件,那么双击时必然会先触发一次单击。
我们的目的是对双击事件单独处理,为此只需引入一个延时机制即可。让计时器在发生WM_XBUTTONDOWN时开始计时,待超时后检查WM_XBUTTONDBLCLK是否已经发生,若已发生则触发双击事件,否则触发单击事件。关键的是延时多久才合适呢?长了没有意义,短了可能超时后WM_XBUTTONDBLCLK都没有发生。显然应该至少延迟双击时两次单击之间的时间间隔,这一时间可以有系统API函数GetDoubleClickTime得到。
 

4.2 解决方案

按照如下几个步骤对通知栏图标控件的代码稍加修改即可(注意WM_XBUTTONUP等消息中的“X”可为“L”、“M”、“B”,表示鼠标左键、中键、右键)。
A.   定义两个变量FMouseDblClicked和FMouseUp,分别用以指示双击和鼠标松开是否已经发生,均初始化为False。
B.   再为TEoCTrayIcon控件添加一个TTimer类成员变量FTimer,并在OnCreate事件中对它进行初始化:
 
constructor TEoCSysTray.Create(AOwner: TComponent);
begin
……
  FMouseDblClicked := False;
  FMouseUp := False;
  FTimer := TTimer.Create(Self);
  with FTimer do
  begin
    Enabled := False;
    Interval := GetDoubleClickTime;     //时钟间隔设为双击的时间间隔。
    OnTimer := OnButtonTimer;           //设置时钟超时响应过程。
  end;
……
end; //end of Create
 
C.   接下来在前述重载的隐藏窗口消息处理过程中响应不同消息来设置上述两个变量的状态。
 
procedure TEoCSysTray.WndProc(var Msg: TMessage);
begin
……
  case Msg.LParam of
    WM_XBUTTONDOWN:
begin
……
FMouseDblClicked := False;//双击尚未发生
FMouseUp := False;       //鼠标尚未松开
FTimer.Enabled := False; //结束上次延时
FTimer.Enabled := True;  //开始延时
end;
    WM_XBUTTONUP:
FMouseUp := True;        //设置鼠标已经松开,便于Timer检查
    WM_XBUTTONDBLCLk:
       begin
FMouseDblClicked := True;       //设置双击已经发生的标志
触发双击事件;
       end;
  else
    Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
  end;
end; //end of WndProc
 
D.   在延时处理程序中判断鼠标状态,触发单击事件。
procedure TEoCSysTray.OnButtonTimer(Sender: TObject);
begin
  FTimer.Enabled := False;
  if (not FMouseDblClicked) and FMouseUp then //双击尚未发生且鼠标已松开
  begin
    触发单击事件;
    触发MouseUp事件;
  end;
end; //end of procedure OnButtonTimer
 
如此一来,单击事件就表现为WM_XBUTTONDOWN, Click, WM_XBUTTONUP,而双击事件则表现为WM_XBUTTONDOWN, WM_XBUTTONDBLCLK(过滤掉了两条MW_XBUTTONUP消息),从而避免了双击事件发生时触发单击事件。
 

5 总结

关于通知栏图标的编程还有很多话题,比如动态切换图标、响应MouseLeave和MouseEnter事件等,在实际中都有应用,难以面面俱到。

文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·ASP.NET2.0连接SQL Server数据库详解-.NET教程,Asp.Net开发
·在.net中轻松掌握Windows窗体间的数据交互-.NET教程,.NET Framework
·Java中的类反射机制-JSP教程,Java技巧及代码
·小技巧让pdf文件与word文档之间自由地转换
·j2ee程序员应该掌握的linux知识-JSP教程,J2EE/EJB/服务器
·通过WMI获得硬盘和CPU的物理序列号(VB.net)-.NET教程,VB.Net语言
·firfox浏览器开发人公开firfox2.0开发计划
·VB.net入门(10):补充:类~属性-.NET教程,VB.Net语言
·office2003实战秘笈之excel轻松制胜招
·C#编码规范.doc-.NET教程,C#语言
最新文章
·天涯试水网络口碑营销 邢明:希望与"关键词"媲美_站长访谈
·美梨网站长冰寒的商务之道_站长访谈
·白手起家 新网站流量快速提高之道_站长心得
·照片处理 photoshop简单制作照片柔光效果_photoshop教程
·网络百戒 ---网页外观_站长心得
·utf-8转换gb2312编码,解决统计google搜索来源关键字乱_google推广
·googleadsense作弊不是技术的较量_google推广
·google改进搜索服务 企业可在local更新资料_google推广
·rss订阅对你的网站搜索表现有好处吗?_站长心得
·15种简洁有效的网站推广方法_站长心得
相关主题
  • windows vista中如何用闪存保护资料_windows vista
  • windows vista sp1新增创建恢复盘功能_windows vista
  • windows vista为什么不允许两个用户同时登录_windows vista
  • windows网络安全其实我们只差五步_安全在线教程
  • windowsxp sp3 概览里面到底有什么?_windows xp
  • 西部数码虚拟主机

    友情链接
    CNNIC 西部数码
    万网 自助建站
    虚拟主机 asp空间
    域名注册 域名
    域名申请 主页空间
    论坛空间 网站空间
    国际域名 虚拟空间
    空间租用 DDOS防火墙
    成都主机托管 四川主机托管
    主机租用 服务器租用
    网站目录 自助建站
    虚拟主机 网址大全
    软件下载
    自助链接
    虚拟主机资讯 特价虚拟主机
    版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
    关于我们:站长天空:专业提供最新的站长资讯、在线教程、虚拟主机权威评测、虚拟主机性能对比、网站制作教程,开发教程,站长工具。包括网页制作教程、冲浪宝典、编程参考、操作系统、软件教学、行业动态等。
    特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
    发表评论 打印  刷新     关闭