Delphi中实现系统托盘的功能

本文介绍了一个Delphi自定义组件TMyTaskTray,该组件用于实现系统托盘功能,包括图标显示、托盘提示、菜单弹出及窗口恢复等操作。组件支持多种触发方式如左双击、右双击等。

如今的Delphi已经TTrayIcon控件直接支持系统托盘了,在这之前都需要写很多代码才能实现。

资料转自网络:http://hi.baidu.com/crazy_net/blog/item/2906203bc3e041ee15cecb93.html

 

unit jin01;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,Forms, ShellApi,
   ExtCtrls,StdCtrls,Menus;

const

//自定义托盘消息

   WM_TrayMsg=WM_USER+10;

type

//恢复窗口的方式,左双击,右双击,左单击,右单击

TRMode=(LDbClick,RDbClick,LCLick,RClick);

TMytaskTray=class(TComponent)

private

//私有成员

    FIcon:TIcon;   //图标

    FDfIcon:THandle; //应用程序的默认图标

    FSetDfIcon:Boolean; //是否用应用程序的图标,如果为True,则Ficon为nil

    FIconData: TNotifyIconData; //托盘数据结构

    FHandle: HWnd; //不可视建窗体句柄,用于处理托盘事件

    FActive: Boolean; //是否启用托盘
    FPopupMenu: TPopupMenu;//弹出菜单

    FHint: string; //托盘提示字符串
    Ficonshow:BOOLean;//如果为true,显示托盘图标
    Ftkshow:BOOLean;//如果为TRUE,任务栏显示

    FRMode:TRMode; //恢复窗口的方式
    Fmenumode:TRMODE; //菜单弹出方式
    Fmousestat: integer;
    OldStyleEX: longInt;
    isClickIn: Boolean;//标识鼠标是否点在图标上

     //保存老的窗口风格

//事件成员

    FOnIconClick: TNotifyEvent;

    FOnIconDblClick: TNotifyEvent;

    FOnIconMouseMove: TMouseMoveEvent;

    FOnIconMouseDown: TMouseEvent;

    FOnIconMouseUp: TMouseEvent;

//设置方法

    procedure SetIcon(value:TIcon);

    procedure SetDfIcon(value:boolean);

    procedure SetActive(value:boolean);

    procedure SetHint(value:string);
    procedure SetPopupMenu( Value: TPopupMenu);
    procedure settkshow(value:boolean);
    procedure Seticonshow(value:boolean);

    procedure SetRMode(value:TRMode);
    procedure setmenumode(value:trmode);
     procedure taskhide;
     procedure taskshow;


//私有方法

procedure SetTray(Way:DWORD);
    function GetActiveIcon:THandle; //取得有用的图标句柄

protected

    //应用程序的消息钩子,获得主窗口的最小化消息

    function AppMsgHook(var Msg:TMessage):Boolean;
     //设置托盘样式,修改,删除,增加
    procedure formshowchange;

    procedure WndProc(var Msg: TMessage);//不可视窗口的窗口过程

    //以下为事件的调度函数

    procedure DblClick; dynamic;

    procedure Click; dynamic;

    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;

    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;

    procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;


public

     isMin:Boolean;//标识是否窗口最小化了
     constructor Create(AOwner:TComponent);override;

     destructor Destroy;override;
     procedure show;        //恢复窗口


published

     property Active:Boolean read FActive write SetActive default False;

     property Icon:TIcon read FIcon write SetICon;

     property SetDfIconed: boolean read FSetDfIcon write SetDfIcon default true;

     property Hint:String read FHint write SetHint;
     property tkshow:boolean read ftkshow write settkshow default false;
     property iconshow: boolean read Ficonshow write Seticonshow default true;

     property RMode:TRmode read FRmode write SetRMode default LDbClick;
      property menuMode:TRmode read Fmenumode write SetmenuMode default Rclick;
     property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
      procedure Notification(AComponent: TComponent; Operation: TOperation); override;


//事件的方法指针

     property OnIconClick: TNotifyEvent read FOnIconClick write FOnIconClick;

     property OnIconDblClick: TNotifyEvent read FOnIconDblClick write FOnIconDblClick;

     property OnIconMouseMove: TMouseMoveEvent read FOnIconMouseMove write FOnIconMouseMove;

     property OnIconMouseDown: TMouseEvent read FOnIconMouseDown write FOnIconMouseDown;

     property OnIconMouseUp: TMouseEvent read FOnIconMouseUp write FOnIconMouseUp;

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents('jinfei', [TMytaskTray]);

end;

///////////Tmytasktray////////////////////////////

constructor Tmytasktray.Create(AOwner:TComponent);

begin

inherited Create(AOwner);

//设置程序钩子,指定AppMsgHook为处理函数,

//则,应用程序的任何消息都将经过这个函数

   Application.HookMainWindow(AppMsgHook);

   FICon:=TICon.Create;

   //得到默认图标的句柄,图标为应用程序的图标

   FDfIcon:=Application.Icon.Handle;

   FSetDfIcon:=True;

   FActive:=False;
   Ficonshow:=true;
   ftkshow:=false;
   FRMode:=LDbClick;
   fmenumode:=Rclick;
   fmousestat:= WM_RBUTTONDOWN;

   isMin:=False;

//创建一个不可视窗口,并指定窗口过程,以处理托盘事件

    FHandle := AllocateHWnd(WndProc);

//保存窗体的老的风格,在恢复窗口的同时也恢复原来的窗口风格

   // OldStyleEX:=GetWindowLong(Application.Handle,GWL_EXSTYLE);
   if not (csDesigning in ComponentState) and ftkshow=false then
         taskhide;

end;

destructor Tmytasktray.Destroy;

begin

Application.UnhookMainWindow(AppMsgHook);

//对象释放之前先消除托盘

    SetTray(NIM_DELETE);

//释放不可能窗口的句柄

DeallocateHWnd(FHandle);

FICon.Free;

inherited Destroy;

end;

//应用程序钩子,可以截获应用程序的所有消息

function Tmytasktray.AppMsgHook(var Msg:TMessage):Boolean;

var placement:WINDOWPLACEMENT;

begin

Result:=False;

//保证程序不会在设计时处理最小化消息
if factive then
begin
if not (csDesigning in ComponentState) then
begin
if (Msg.Msg=WM_SYSCOMMAND) then

begin

   if msg.WParam=SC_MINIMIZE Then

    begin

    //设置了这个属性后,窗口最小化就不会停在任务栏了,而是停在屏幕,

    //位置由SetWindowPlacement来决定
     OldStyleEX:=GetWindowLong(Application.Handle,GWL_EXSTYLE);
     ShowWindow(Application.Handle,SW_HIDE);
    if ftkshow=false then
     SetWindowLong(Application.Handle,GWL_EXSTYLE      ,WS_EX_TOOLWINDOW);

     GetWindowPlacement(Application.Handle,@placement);

     placement.flags:=WPF_SETMINPOSITION;

     placement.ptMinPosition.x:=1050;

     placement.ptMinPosition.y:=800;

     SetWindowPlacement(Application.Handle,@placement);
      ismin:=true;
      end;
end;
end;
if ficonshow=false then
          SetTray(NIM_DELETE)
          else SetTray(NIM_ADD );

end
else
    settray(NIM_DELETE);

end;
//设置托盘方式,显示,修改,删掉,重要方法
procedure Tmytasktray.SetTray(Way:DWORD);

begin

   FIconData.cbSize:=Sizeof(FIconData);

   FIconData.Wnd:=FHandle;

   FIConData.uID:=0;

   FIConData.uFlags:=NIF_ICON or NIF_MESSAGE or NIF_TIP;

   FIConData.uCallbackMessage:=WM_TrayMsg;

   FIConData.hIcon:=GetActiveIcon;

   StrLCopy(FIConData.szTip,Pchar(FHint),63);

   Shell_NotifyIcon(Way,@FIconData);

end;


//取得可用的图标


procedure Tmytasktray.SetIcon(Value:TIcon);

begin

   FIcon.Assign(Value);

   FsetDfIcon:=False; //有了自定义的图标,则默认图标自动设为False

   if FIcon.Empty then

    FsetDfIcon:=True;

   if (isMin)and(Factive) then

     SetTray(NIM_MODIFY );

end;

//设置是否为默认图标,与FIcon为互相的变量,只能有其中一个

procedure Tmytasktray.SetDfIcon(Value:Boolean);

begin

    FSetDfIcon:=Value;

    if not FSetDfIcon then

     begin

      if FIcon.Empty then begin

        FSetDfIcon:=True;

        exit;

      end;
     end

    else begin

        if (IsMin)and(FActive) then

         SetTray(NIM_MODIFY);

    end;


end;

procedure Tmytasktray.SetPopupMenu( Value: TPopupMenu);
begin
FPopupMenu := Value;
if Value <> nil then Value.FreeNotification(Self);
end;

procedure Tmytasktray.SetActive(Value:Boolean);

begin
   FActive:=Value;
    if not (csDesigning in ComponentState) then
         if factive=false then
          begin SetTray(NIM_DELETE);
       taskshow;
          end;


end;
procedure Tmytasktray.settkshow(value:boolean);
begin
        if factive=true then
        begin
           ftkshow:=value;
           if not (csDesigning in ComponentState) then
           if ftkshow=false then
             taskhide
            else
            taskshow;

         end;

end;


procedure Tmytasktray.SetHint(Value:String);

begin

     FHInt:=Value;

     if (IsMin)and(FActive) then

        SetTray(NIM_MODIFY);


end;
procedure Tmytasktray.Seticonshow(Value:Boolean);

begin
    if factive=true then
    begin
    Ficonshow:=Value;
      if ficonshow=false then
          SetTray(NIM_DELETE)
          else SetTray(NIM_ADD );
    end;
end;

procedure Tmytasktray.show;

begin
    if factive=true then
   formshowchange();

end;


procedure Tmytasktray.SetRMode(Value:TRMode);

begin

    FRmode:=Value;

end;

procedure Tmytasktray.SetmenuMode(Value:TRMode);

begin

    Fmenumode:=Value;
    case fmenumode of
   Lclick: fmousestat:=WM_LBUTTONdown;
   Ldbclick: fmousestat:=wm_LBUTTONDBLCLK;
   Rclick :   fmousestat:=Wm_rbuttondown;
   rdbclick: fmousestat:=WM_RBUTTONDBLCLK;
   end

end;

procedure Tmytasktray.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = fPopupMenu) then
    fPopupMenu := nil;
end;

function Tmytasktray.GetActiveIcon:THandle;

begin

   if not FSetDfIcon then

     result:=FIcon.Handle

   else

     result:=FDfIcon;

end;

//托盘消息的截获,以调用相应的事件调度方法


procedure Tmytasktray.WndProc(var Msg: TMessage);

var p:TPoint;

begin
if (Msg.Msg=WM_TrayMsg)and(FActive) then

begin
     if fmousestat=Msg.LParam then
         begin
          if Assigned(FPopupMenu) then
          begin
            SetForegroundWindow( FHandle); // 这句一定要加,否则弹出菜单不会自动隐藏
            GetCursorPos(P);
            FPopupMenu.Popup(P.X, P.Y);
          end;
          end;


    case Msg.LParam of

      WM_LBUTTONDBLCLK://左双击

      begin

        GetCursorPos(p);

        DblClick;

        MouseDown(mbLeft, KeysToShiftState(TWMMouse(Msg).Keys)+[ssDouble], P.X, P.Y);

        if FRmode=LDbclick then

        begin

      formshowchange();

        end;

      end;

      WM_RBUTTONDBLCLK://右双击

      begin

        GetCursorPos(P);

        DblClick;

        MouseDown(mbRight, KeysToShiftState(TWMMouse(Msg).Keys)+[ssDouble], P.X, P.Y);

        if FRmode=RDbclick then

        begin

      formshowchange();

        end;

      end;

      WM_MOUSEMOVE: //鼠标移动

      begin

        GetCursorPos(P);

        MouseMove(KeysToShiftState(TWMMouse(Msg).Keys), P.X, P.Y);

      end;

      WM_LBUTTONDOWN: //左单击下

      begin

        GetCursorPos(P);

        IsClickIn:=True;

        MouseDown(mbLeft, KeysToShiftState(TWMMouse(Msg).Keys) + [ssLeft], P.X, P.Y);

      end;

      WM_LBUTTONUP: //左单击弹起

      begin

        GetCursorPos(P);

        if IsClickIn then

        begin

          IsClickIn:=False;

          Click;

          if FRmode=LClick then

          begin

          formshowchange();

          end;

        end;

          MouseUp(mbLeft, KeysToShiftState(TWMMouse(Msg).Keys)+ [ssLeft], P.X, P.Y);

      end;

      WM_RBUTTONDOWN: //右单击下

      begin

        GetCursorPos(P);

        IsClickIn:=True;

        MouseDown(mbRight, KeysToShiftState(TWMMouse(Msg).Keys) + [ssRight], P.X, P.Y);

      end;

      WM_RBUTTONUP: //右单击弹起

      begin

        GetCursorPos(P);

        if IsClickIn then

        begin

          IsClickIn:=False;

          Click;

          if FRmode=RClick then

          begin

       formshowchange();

          end;

        end;

        MouseUp(mbRight, KeysToShiftState(TWMMouse(Msg).Keys)+ [ssRight], P.X, P.Y);

       end;

      end;

end

else

     Msg.Result := DefWindowProc(FHandle, Msg.Msg, Msg.wParam, Msg.lParam);


end;
procedure tmytasktray.formshowchange;
begin
         
    if ismin=true then
        begin

            //    if ftkshow=false then
            //      taskhide;
              //    else
         // ShowWindow(Application.Handle,SW_SHOW);

          //这里很重要的一个就是恢复窗口风格,不然下次把Active设为True

          //最小化后,窗口依然会往左下角飞去,而托盘图标却看不见了.

         SetWindowLong(Application.Handle,GWL_EXSTYLE    ,OldStyleEX);


          SendMessage(Application.Handle,WM_SYSCOMMAND,SC_RESTORE,0);
           if ftkshow=false then
               taskhide;
              
           ismin:=false;
        end;
         
end;

//以下为几个事件的调度函数,比较简单.

procedure Tmytasktray.DblClick;

begin

if Assigned(FOnIconDblClick) then

    FOnIconDblClick(Self);

end;

procedure Tmytasktray.Click;

begin

if Assigned(FOnIconClick) then

    FOnIconClick(Self);

end;

procedure Tmytasktray.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

begin

if Assigned(FOnIconMouseDown) then

    FOnIconMouseDown(Self, Button, Shift, X, Y);

end;

procedure Tmytasktray.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

begin

if Assigned(FOnIconMouseUp) then

    FOnIconMouseUp(Self, Button, Shift, X, Y);

end;
procedure Tmytasktray.taskhide;
begin
ShowWindow(Application.Handle,SW_HIDE);
SetWindowLong(Application.Handle,GWL_EXSTYLE, WS_EX_TOOLWINDOW);

end;
procedure tmytasktray.taskshow;
begin
//SetWindowLong(Application.Handle,GWL_EXSTYLE    ,OldStyleEX);
// SendMessage(Application.Handle,WM_SYSCOMMAND,SC_RESTORE,0);
ShowWindow(Application.Handle,SW_SHOW);
SetWindowLong(Application.Handle,GWL_EXSTYLE, WS_EX_APPWINDOW);
end;
procedure Tmytasktray.MouseMove(Shift: TShiftState; X, Y: Integer);

begin

if Assigned(FOnIconMouseMove) then

    FOnIconMouseMove(Self, Shift, X, Y);

end;

end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值