CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  Delphi >  VCL组件开发及应用

如何编写一个systray程序?方法及主意事项

楼主which(which)2002-04-30 10:58:08 在 Delphi / VCL组件开发及应用 提问

希望大家给我一些指教。我想写一个比较健壮实用的systray程序。 问题点数:100、回复次数:5Top

1 楼plainsong(短歌)()回复于 2002-04-30 11:16:19 得分 50

...\delphi5\source\vcl\scktsrvr.dpr是一个很好的例子,你可以参照修改一下.  
  我自己也作了一个,你要的话我可以发给你.Top

2 楼forgot(忘记forgot2000)回复于 2002-04-30 11:36:56 得分 30

windows   95   和   windows   nt   4.0包含一个令人兴奋的特性:任务栏。这个通常位于区域任务条右面的区域能包含小的图标,这些图标能引出大的应用程序或者菜单。本篇文章主要讨论如何使用delphi建立这样的应用程序。    
          在开始之前,请看下面的需要的接口方面的内容:    
   
          从技术方面来说,一个任务栏应用程序非常象普通的应用程序,它有一个消息循环,相应windows的消息来完成相应的功能。    
   
  procedure   runtrayapplication;  
  var   msg   :   tmsg;  
  begin  
      createwindow;  
      addtrayicon;  
      while   getmessage(msg,0,0,0)   do   begin  
          translatemessage(msg);  
          dispatchmessage(msg);  
      end;  
      deletetrayicon;  
  end;  
          你能看到:所有需要做的工作是创建一个窗口,注册一个图标到任务栏,设置它的消息循环,最后关闭它。当然,必须还有增加其他代码完成相应的功能,但是,它是真的不需要担心。    
   
          让我们从窗口的创建开始。实际上,这个窗口是不是能在任务栏上能见到的窗口。相应的,这个窗口只是处理消息循环、其它父类的工作。任务窗口(windows   95   &   nt)句柄创建消息(例如鼠标单击等)和将消息发到我们的窗口。    
   
  procedure   createwindow;  
  var  
      wc   :   twndclass;  
      w     :   hwnd;  
  begin  
      with   wc   do   begin  
          style   :=   0;  
          lpfnwndproc   :=   @wndproc;  
          cbclsextra   :=   0;  
          cbwndextra   :=   0;  
          hicon   :=   0;  
          hcursor   :=   0;  
          hbrbackground   :=di2001.jpg;  
          lpszmenuname   :=   nil;  
          lpszclassname   :=   'mytrayiconclass';  
          hinstance   :=   system.hinstance;  
      end;  
      registerclass(wc);  
      w   :=   windows.createwindow('mytrayiconclass',   'myveryowntrayiconwindow',  
                                                          ws_overlappedwindow,   0,   0,   0,   0,   0,   0,   hinstance,   nil);  
      showwindow(w,sw_hide);  
      updatewindow(w);  
      mainwindow   :=   w;  
  end;  
     
   
          这个窗口使用普通的窗口函数创建。注意这个窗口的类型是“ws_overlappedwindow”,但是这个尺寸是0,并且它是隐藏的,所有,它将不会显示出来。    
   
          下一步是加(注册)我们的图标。这将需要使用shell_notifyicon这个api函数,这个函数实际上可以完成三个功能,这里只需要它的增加的特性。    
   
  procedure   addtrayicon;  
  var   icondata   :   tnotifyicondata;  
  begin  
      with   icondata   do   begin  
          cbsize   :=   sizeof(icondata);  
          wnd   :=   mainwindow;  
          uid   :=   0;  
          uflags   :=   nif_icon   or   nif_message   or   nif_tip;  
          ucallbackmessage   :=   wm_mycallback;  
          hicon   :=   loadicon(hinstance,'myicon');  
          strcopy(sztip,pchar(trayicontip));  
      end;  
      shell_notifyicon(nim_add,@icondata);  
  end;  
     
   
          这个最重要的事情是tnotifyicondata的数据结构,它是一个设置window句柄的数据结构,是一个记录参数,对我们来说,我们需要设置这个图标的窗口句柄(这将定义哪个窗口处理消息循环),回调消息号,图标,工具提示等。一旦这个数据设置了,我们就可以增加一个图标到任务栏上了。为了完成这个工作,使用nim_add程序。    
   
          现行我们已经加了我们的图标到任务栏,下面需要决定如何处理消息。    
   
  const  
      wm_mycallback   =   wm_user+1000;  
      cm_exit               =   100;   {   we   worry   about...   }  
      cm_about             =   101;   {   ...these   later         }  
     
   
          这个实际的窗口处理过程也是相当普通。几个窗口消息(如wm_nccreate)必须处理。然而,对我们来说,更重要的事情是处理wm_mycallback和wm_command消息:    
   
  function   wndproc   (window   :   hwnd;   msg,   wparam,   lparam   :   integer):   integer;   stdcall;  
  begin  
      result   :=   0;  
      case   msg   of  
          wm_nccreate       :   result   :=   1;  
          wm_destroy         :   postquitmessage(0);  
          wm_command         :   begin   {   a   command   was   chosen   from   the   popup   menu   }  
                                              if   (wparam   =   cm_exit)   then  
                                                  postmessage(window,wm_destroy,0,0)  
                                              else   if   (wparam   =   cm_about)   then  
                                                  messagebox(0,'shell   test   copyright   ?'+  
                                                                        'jani   j鋜vinen   1996.',  
                                                                        'about   shell   test',mb_ok)  
                                              else   opendesktopicon(wparam-cm_about);  
                                          end;  
          wm_mycallback   :   begin   {   our   icon   was   clicked   }  
                                              if   (lparam   =   wm_lbuttondown)   then  
                                                  showiconpopupmenu  
                                              else   if   (lparam   =   wm_rbuttondown)   then  
                                                  showaboutpopupmenu;  
                                          end;  
          else   result   :=   defwindowproc(window,msg,wparam,lparam);  
      end;  
  end;  
     
   
          就象你看到的一样,当用户单击图标时,windows提示我们。注意我们不使用通常使用的wm_lbuttondown   消息,而使用wm_mycallback   message,详细的消息信息存储在lparam参数中。    
   
          当用户单击鼠标右键,我们创建一个菜单在桌面上。    
   
  type  
      ticondata   =   array[1..100]   of   string;  
  var  
      icondata       :   ticondata;  
  procedure   showiconpopupmenu;  
  var  
      shellfolder   :   ishellfolder;  
      enumidlist     :   ienumidlist;  
      result             :   hresult;  
      dummy               :   ulong;  
      itemidlist     :   titemidlist;  
      pntr                 :   pitemidlist;  
      strret             :   tstrret;  
      popupmenu       :   hmenu;  
      itemid             :   integer;  
      pos                   :   tpoint;  
      procedure   addtomenu(item   :   string);  
      var   s   :   string;  
      begin  
          icondata[itemid-cm_about]   :=   item;  
          s   :=   extractfilename(item);  
          if   (system.pos('.',s)   <>   0)   then   setlength(s,system.pos('.',s)-1);  
          appendmenu(popupmenu,mf_enabled   or   mf_string,itemid,pchar(s));  
          inc(itemid);  
      end;  
  begin  
      popupmenu   :=   createpopupmenu;  
      itemid   :=   cm_about+1;  
      shgetdesktopfolder(shellfolder);  
      shellfolder.enumobjects(mainwindow,shcontf_nonfolders,enumidlist);  
      pntr   :=   @itemidlist;  
      result   :=   enumidlist.next(1,pntr,dummy);  
      while   (result   =   noerror)   do   begin  
          shellfolder.getdisplaynameof(pntr,shgdn_forparsing,@strret);  
          with   strret   do   addtomenu(string(cstr));  
          result   :=   enumidlist.next(1,pntr,dummy);  
      end;  
      enumidlist.release;  
      shellfolder.release;  
      getcursorpos(pos);  
      appendmenu(popupmenu,mf_separator,0,'');  
      appendmenu(popupmenu,mf_enabled   or   mf_string,cm_exit,'e&xit');  
      setforegroundwindow(mainwindow);  
      trackpopupmenu(popupmenu,tpm_leftalign   or   tpm_leftbutton,  
                                    pos.x,pos.y,0,mainwindow,nil);  
      destroymenu(popupmenu);  
  end;  
     
   
          上面的程序看起来有点复杂,你可以将它分成两个部分来看:创建和显示菜单。    
   
          列举创建菜单是用windows的外壳接口完成的。首先,我们使用shgetdesktopforlder函数得到使用桌面的ishellfolder接口。使用这个接口,我们能得到另一个接口的实例:ienumidlist。这个接口通常实现实际的列举工作。我们简单的重复调用这个函数直到错误值返回(例如:所有的菜单被列举)。当我们得到一个菜单,我们使用addtomenu函数加它。    
   
          当所有的菜单被列举和创建后,现在我们需要运行这个菜单。我们将找到的菜单保存到一个全局的list变量中,每一个菜单都拥有它的菜单号。这确保我们能得到它的索引。    
   
              opendesktopicon(wparam-cm_about)    
   
  当然,wparam中储存了用户单击鼠标的菜单的菜单号(id)。    
   
          下面我们将处理运行用户选择的菜单。    
   
  procedure   opendesktopicon(number   :   integer);  
  var  
      s   :   string;  
      i   :   integer;  
  begin  
      s   :=   icondata[number];  
      i   :=   shellexecute(0,nil,pchar(s),nil,nil,sw_shownormal);  
      if   (i   <   32)   then   begin  
          s   :=   'could   not   open   selected   item   "'+s+'".   '+  
                    'result   was:   '+inttostr(i)+'.';  
          messagebox(0,pchar(s),'shell   test',mb_ok);  
      end;  
  end;  
     
   
          上面,win   32   api函数shellexecute做了所有的工作。    
   
          现在你应该能用delphi创建简单的任务栏的程序了。    
  Top

3 楼cg1120(代码最优化-§惟坚韧者始能遂其志§)回复于 2002-04-30 11:40:26 得分 20

在Shell32.DLL动态链接库中包括一个函数Shell_NotifyIconA()可通知Windows在任务条右下角加入一个小图标,下面以一个简单的实例来说明如果使用该函数:    
   
  unit   Unit1;    
   
  interface    
   
  {   记住在uses部分中包括   ShellAPI}    
  uses    
  Windows,   Messages,   SysUtils,   Classes,    
  Graphics,   Controls,   Forms,   Dialogs,    
  ShellAPI,   StdCtrls;    
   
  {自定义消息,当小图标捕捉到鼠标事件时Windows向回调函数发送此消息}    
  {自定义消息,当小图标捕捉到鼠标事件时Windows向回调函数发送此消息}    
  const   MY_MESSAGE   =   WM_USER   +   100;    
   
  type    
  TForm1   =   class(TForm)    
  procedure   FormCreate(Sender:   TObject);    
  procedure   FormClose(Sender:   TObject;   var   Action:   TCloseAction);    
  procedure   FormPaint(Sender:   TObject);    
  private    
  procedure   OnIconNotify(var   Message:   TMessage);    
  message   MY_MESSAGE;    
  public    
  {   Public   declarations   }    
  end;    
   
  var    
  Form1:   TForm1;    
   
  implementation    
   
  {$R   *.DFM}    
   
   
  {当小图标捕捉到鼠标事件时进入此过程}    
  {当小图标捕捉到鼠标事件时进入此过程}    
  procedure   TForm1.OnIconNotify(var   Message:   TMessage);    
  const    
  Busy:   Boolean   =   false;    
  begin    
  if   not   Busy   then   begin    
  Busy   :=   true;    
  if   Message.LParam=WM_LBUTTONDOWN   then    
  if   Application.MessageBox('Are   you   sure',    
  'Exit',   MB_YESNO)=IDYES   then   Close;    
  Busy   :=   false;    
  end;    
  end;    
   
  {当主Form建立时通知Windows加入小图标}    
  procedure   TForm1.FormCreate(Sender:   TObject);    
  var    
  nid:   TNotifyIconData;    
  begin    
  nid.cbSize   :=   sizeof(nid);   //   nid变量的字节数    
  nid.Wnd   :=   Handle;   //   主窗口句柄    
  nid.uID   :=   -1;   //   内部标识,可设为任意数    
  nid.hIcon   :=   Application.Icon.Handle;   //   要加入的图标句柄,可任意指?  
  nid.hIcon   :=   Application.Icon.Handle;   //   要加入的图标句柄,可任意指?  
   
  nid.szTip   :=   'This   is   a   test   application';   //   提示字符串    
  nid.uCallbackMessage   :=   MY_MESSAGE;   //   回调函数消息    
  nid.uFlags   :=   NIF_ICON   or   NIF_TIP   or   NIF_MESSAGE;   //   指明哪些字段有?  
   
  if   not   Shell_NotifyIcon(NIM_ADD,   @nid)   then   begin    
  ShowMessage('Failed!');    
  Application.Terminate;    
  end;    
  {将程序的窗口样式设为TOOL窗口,可避免在任务条上出现}    
  SetWindowLong(Application.Handle,   GWL_EXSTYLE,   WS_EX_TOOLWINDOW);    
  end;    
   
  {程序被关闭时通知Windows去掉小图标}    
  procedure   TForm1.FormClose(Sender:   TObject;   var   Action:   TCloseAction);    
  var    
  nid:   TNotifyIconData;    
  begin    
  nid.cbSize   :=   sizeof(nid);   //   nid变量的字节数    
  nid.cbSize   :=   sizeof(nid);   //   nid变量的字节数    
  nid.uID   :=   -1;   //内部标识,与加入小图标时的数一致    
  nid.Wnd   :=   Handle;   //主窗口句柄    
  Shell_NotifyIcon(NIM_DELETE,   @nid);   //去掉小图标    
  Shell_NotifyIcon(NIM_DELETE,   @nid);   //去掉小图标    
  end;    
   
  {主窗口初始化完毕并显示时将激活Paint重画事件,此时将主窗口隐藏}    
  procedure   TForm1.FormPaint(Sender:   TObject);    
  begin    
  Hide;    
  end;    
   
  end.Top

4 楼Borland_Delphi(老虎)回复于 2002-04-30 11:41:38 得分 0

搜索一下就有N多答案了哦Top

5 楼which(which)回复于 2002-04-30 12:56:56 得分 0

谢谢各位的帮助,plainsong(轻风)   ,我的地址是sz_zw@sina.com,我刚刚开始用delphi,希望可以和大家多多交流,多多学习。Top

相关问题

  • 月底要去黄山了 有什么主意事项么(UP有分)
  • 百分以求Dephi开发的网站、以及程序编写的注意事项、重大的要避免的Bug~!!!
  • 给个主意
  • 高分!我要做个的人事管理系统,我想知道数据库应该有些什么项目!要主意什么事项!路过的来看看发表下看法!UP有分!
  • 如何编写
  • 编写DLL
  • 编写lotusscript
  • 注意事项
  • 关于编写Plugin
  • JSP编写工具.

关键词

  • 函数
  • 消息
  • 接口
  • 应用程序
  • 循环
  • 菜单
  • enumidlist
  • pntr
  • shellfolder
  • 图标

得分解答快速导航

  • 帖主:which
  • plainsong
  • forgot
  • cg1120

相关链接

  • Delphi类图书
  • Delphi类源码下载
  • Delphi控件下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo