Programming and Application(编程与应用)


Content(目录)




Linux


MySQL
Office















 
PCNow 30-Day Free Trial, Remote PC Access
 
Logo_234x60

DELPHI对Windows系统状态栏编程


DELPHI对Windows系统状态栏编程

河南济源  董占山

最近在网上各编程社区漫游时,发现时常有朋友提出用Delphi对Windows系统状态栏(也称为托盘区,指任务
栏右边显示时间和输入法图标的区域)进行编程的问题,在实际工作中,这确实是一个较为常见的事情。一般
来讲,每个图标代表一个正在运行的进程(或程序)。用鼠标点击这些图标,或弹出一个窗口或显示一个菜单
,用户可以对特定的任务进行设置和操作。Delphi可以编写只在系统状态栏显示一个图标的应用程序,并将应
用程序隐藏起来,不在任务栏和任务列表中显示。

1	托盘区组件TTrayIcon

对系统状态栏编程需要使用ShellApi中的Shell_NotifyIcon 函数和数据结构TNOTIFYICONDATA。另外还需要
一组Windows API函数来实现隐应用程序的主窗口。实际编写起来并非易事,为了简化应用,已有多个组件出
现,例如RX Library, TTrayIcon等。但是,当笔者试用之后,发现他们都存在不同程度的缺陷,就以
TTrayIcon组件的源码为基础进行了大量的改进,形成一个功能更加强大的组件, 现将其奉献给大家,源码如
下。

TrayIcon.Pas

unit TrayIcon;

interface

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls, ShellAPI, Forms,
  Menus, ExtCtrls, Dialogs ;

const WM_TOOLTRAYICON = WM_USER+1;
      WM_RESETTOOLTIP = WM_USER+2;

type
  TTrayIcon = class(TComponent)
  private
    IconData: TNOTIFYICONDATA;
    fAnimate : boolean ;
    fAnimateInterval : integer ;
    fCurrentImage : integer ;
    fIcon : TIcon;
    fOriginalIcon : TIcon ; // 保存原来的图标
    fToolTip : String;
    fWindowHandle : HWND;
    fActive : boolean;
    fShowDesigning : Boolean;
    fTimer : TTimer ;
    fOnClick     : TNotifyEvent;
    fOnDblClick  : TNotifyEvent;
    fOnRightClick : TMouseEvent;
    fPopupMenu   : TPopupMenu;
    fImages : TImageList ;
fMainWin : TForm; // 保存主窗口

    function AddIcon : boolean;
    function ModifyIcon : boolean;
    function DeleteIcon : boolean;

    procedure SetActive(Value : boolean);
    procedure SetAnimate(Value : boolean);
    procedure SetAnimateInterval(Value : integer);
    procedure SetShowDesigning(Value : boolean);
    procedure SetIcon(Value : TIcon);
    procedure SetToolTip(Value : String);
    procedure SetMainWin(Value : TForm);
    procedure WndProc(var msg : TMessage);

    procedure FillDataStructure;
    procedure DoRightClick( Sender : TObject );
    procedure ChangeIcon( Sender : TObject ) ;
    // onShow event handler for main window
    procedure HideMainWin(Sender: TObject);

  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override ;

  public
    constructor Create(AOwner : TComponent); override;
    destructor Destroy; override;

  published
    property Active : boolean read fActive write SetActive default true;
    property Animate : boolean read fAnimate write SetAnimate ;
    property AnimateInterval : integer read fAnimateInterval write SetAnimateInterval
    default 100;
    property ShowDesigning : boolean read fShowDesigning write SetShowDesigning;
    property Icon : TIcon read fIcon write SetIcon;
    property Images : TImageList read fImages write fImages ;
    property ToolTip : string read fTooltip write SetToolTip;
    property MainWindow : TForm read fMainWin write SetMainWin;

    property OnClick     : TNotifyEvent read FOnClick write FOnClick;
    property OnDblClick  : TNotifyEvent read FOnDblClick write FOnDblClick;
    property OnRightClick : TMouseEvent  read FOnRightClick write FonRightClick;
    property PopupMenu : TPopupMenu read fPopupMenu write fPopupMenu;
  end;

procedure Register;

implementation

{$R TrayIcon.res}

procedure TTrayIcon.Notification(AComponent: TComponent; Operation: TOperation);
begin
   if (AComponent = FImages) and (Operation = opRemove) then begin
      Animate := False ;
      FImages := nil ;
   end ;
end;

procedure TTrayIcon.SetActive(Value : boolean);
begin
   if value <> fActive then begin
     fActive := Value;
     if not (csdesigning in ComponentState) then begin
        if Value then
           AddIcon
        else
           DeleteIcon;
     end;
  end;
end;

procedure TTrayIcon.SetShowDesigning(Value : boolean);
begin
  if csdesigning in ComponentState then begin
     if value <> fShowDesigning then begin
        fShowDesigning := Value;
        if Value then
           AddIcon
        else
           DeleteIcon ;
     end;
  end;
end;

procedure TTrayIcon.SetIcon(Value : Ticon);
begin
  if Value <> fIcon then begin
     fIcon.Assign(value);
     ModifyIcon;
  end;
end;

procedure TTrayIcon.SetAnimate(Value : boolean);
begin
   if (not Value) or ((fImages <> nil) and (fImages.Count > 0) and fActive) then
   begin
      fAnimate := Value ;
      if Value then begin
         fOriginalIcon.Assign(fIcon) ;
         fCurrentImage := 0 ;
      end ;
      fTimer.Enabled := Value ;
      if not Value then
         SetIcon(fOriginalIcon) ;
   end ;
end ;

procedure TTrayIcon.SetAnimateInterval(Value : integer);
begin
   if Value > 0 then begin
      fAnimateInterval := Value ;
      fTimer.Interval := Value ;
   end ;
end ;

procedure TTrayIcon.SetToolTip(Value : string);
begin
   if length( Value ) > 62 then
      Value := copy(Value,1,62);
   fToolTip := value;
   ModifyIcon;
end;

procedure TTrayIcon.SetMainWin(Value : TForm);
var
  AppIcon : TIcon;
begin
  if (Value <> nil) then begin
    fMainWin := Value;
    AppIcon := TIcon.Create;
    AppIcon.Handle := LoadIcon( HInstance ,pchar('MainIcon') );
    Icon := AppIcon;
    AppIcon.Free;
    fMainWin.OnShow := HideMainWin;
    end;
end;

constructor TTrayIcon.Create(AOwner : TComponent);
begin
  inherited ;
  FWindowHandle := AllocateHWnd( WndProc );
  FIcon := TIcon.Create;
  FOriginalIcon := TIcon.Create ;
  FAnimateInterval := 100 ;
  FTimer := TTimer.Create(self) ;
  Active := True;
  FTimer.Enabled := False ;
  FTimer.OnTimer := ChangeIcon;
  if Owner is TForm then begin
    MainWindow := TForm(Owner);
    Active := True;
    end
  else
    MainWindow := nil;
  ToolTip := 'TrayIcon1';
end;

destructor TTrayIcon.Destroy;
begin
  if (not (csDesigning in ComponentState) and fActive)
     or ((csDesigning in ComponentState) and fShowDesigning) then
        DeleteIcon ;
  FTimer.Free ;
  FIcon.Free;
  FOriginalIcon.Free ;
  DeAllocateHWnd(FWindowHandle );
  inherited ;
end;

procedure TTrayIcon.HideMainWin(Sender: TObject);
begin
  if not (csDesigning in ComponentState) then begin
    ShowWindow(Application.handle, SW_HIDE);
    ShowWindowAsync(fMainWin.Handle, SW_HIDE );
    SetWindowPos(fMainWin.Handle, HWND_BOTTOM, -500, 0, fMainWin.Width, fMainWin.Height,
    SWP_HIDEWINDOW + SWP_NOSIZE);
    end;
end;

procedure TTrayIcon.FillDataStructure;
begin
  with IconData do begin
     cbSize := sizeof(TNOTIFYICONDATA);
     wnd := FWindowHandle;
     uID := 0;
     uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
     hIcon := fIcon.Handle;
     StrPCopy(szTip,fToolTip);
     uCallbackMessage := WM_TOOLTRAYICON;
  end;
end;

function TTrayIcon.AddIcon : boolean;
begin
   FillDataStructure;
   result := Shell_NotifyIcon(NIM_ADD,@IconData);
   if fToolTip = '' then
      PostMessage( fWindowHandle, WM_RESETTOOLTIP,0,0 );
end;

function TTrayIcon.ModifyIcon : boolean;
begin
   FillDataStructure;
   if fActive then
      result := Shell_NotifyIcon(NIM_MODIFY,@IconData)
   else
      result := True;
end;

procedure TTrayIcon.DoRightClick( Sender : TObject );
var MouseCo: Tpoint;
begin
   GetCursorPos(MouseCo);
   if assigned( fPopupMenu ) then begin
      SetForegroundWindow( Application.Handle );
      Application.ProcessMessages;
      fPopupmenu.Popup( Mouseco.X, Mouseco.Y );
   end;
   if assigned( FOnRightClick ) then
      begin
         FOnRightClick(self,mbRight,[],MouseCo.x,MouseCo.y);
      end;
end;

function TTrayIcon.DeleteIcon : boolean;
begin
   result := Shell_NotifyIcon(NIM_DELETE,@IconData);
end;

procedure TTrayIcon.WndProc(var msg : TMessage);
begin
   with msg do
     if (msg = WM_RESETTOOLTIP) then
        SetToolTip( fToolTip )
     else if (msg = WM_TOOLTRAYICON) then begin
        case lParam of
           WM_LBUTTONDBLCLK   : if assigned (FOnDblClick) then FOnDblClick(self);
           WM_LBUTTONUP       : if assigned(FOnClick)then FOnClick(self);
           WM_RBUTTONUP       : DoRightClick(self);
        end;
     end
     else // Handle all messages with the default handler
        Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;

procedure TTrayIcon.ChangeIcon( Sender : TObject ) ;
var
   TempIcon : TIcon ;
begin
    TempIcon := TIcon.Create ;
    if fCurrentImage = fImages.Count - 1 then
       fCurrentImage := 0
    else
       Inc(fCurrentImage) ;
    fImages.GetIcon(fCurrentImage, TempIcon) ;
    SetIcon(TempIcon) ;
    TempIcon.Free ;
end ;

procedure Register;
begin
  RegisterComponents('Samples', [TTrayIcon]);
end;

end.

2	组件的安装与使用

2.1	组件的安装

首先将TrayIcon.Pas和TrayIcon.RES两个文件复制到C:\Program Files\Borland\Delphi5\UserLib\目录
(DELPHI默认的用户组件库目录)下。启动Delphi,单击"Component"菜单中的"Install Component"菜单命
令,弹出图 1所示的安装组件对话窗口。将"Unit file name"设置为"C:\Program
Files\Borland\Delphi5\UserLib\Trayicon.pas"或组件源文件所在的位置,将"Package file name"设置
为"c:\program files\borland\delphi5\userlib\UserLib.dpk",单击"OK"按钮,DELPHI自动安装该组件
,并告诉你安装的结果。

图 1  安装组件对话窗口

2.2	使用说明

该组件的使用极其简单,当程序的主窗体建立好后,只需要简单地选中"Samples"组件页上的TrayIcon组件,
在窗体上放置一个"TrayIcon"组件,可看到如图 2所示的对象监视窗口,"MainWindow"属性已经自动设置成当
前的窗体了,而且"Icon"属性也设置成程序的默认图标。你需要做的是在主窗口上添加一个PopupMenu组件,
并在其中添加"Exit"、"Setup"和"Pause"等命令并编写相应的事件处理程序。然后,就可以编译运行这个简单
的示例程序。当程序图标在系统状态栏显示后,用鼠标右键单击该图标就可以显示一个弹出菜单,用来控制应
用程序。

图 2  对象监视窗口

3	小结

在使用DELPHI编程时,我们不妨将一些重复使用的常用代码组织起来,写成组件,放到DELPHI的组件板上,这
样,在使用时只需要将组件加到窗体上,并进行必要的设置,就可以完成特定的功能了,免去了重复拷贝代码
和修改类似代码的痛苦。该组件和示例程序在DELPHI 5.0+WINDOWS 98环境下调试通过。
©董占山Zhanshan Dong

Post comments(留言)

Name(名字):

Comment(内容):


由Google提供

SunfineData Products|U's Bargain Network|Contact Me(与我联系)
© 1998-, 董占山, 版权所有, 欢迎转载文章链接。
转载文章和软件请注明出处(http://articles.sunfinedata.com/)。