在编写一个托盘程序中,往往需要创建、修改、移除托盘图标,从这里开始入手。
一、创建、修改、移除托盘图标,只需调用一个API函数,Shell_NotifyIcon(),这个函数向windows操作系统发送一个消息,要求windows执行添加、修改、删除某个任务栏状态区图标的操作。这个函数包含在ShellAPI单元中,定义:
function Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL; stdcall;
1.1第一个参数dwMessage: DWORD的取值是在ShellAPI单元中定义的 常量 
const
  {$EXTERNALSYM NIM_ADD}
  NIM_ADD         = $00000000; 
  {$EXTERNALSYM NIM_MODIFY}    
  NIM_MODIFY      = $00000001; 
  {$EXTERNALSYM NIM_DELETE}
  NIM_DELETE      = $00000002; 

NIM_ADD         //添加一个图标到任务栏状态区
NIM_MODIFY  //修改图标
NIM_DELETE    //删除图标

2.1第二个参数lpData: PNotifyIconData是TNotifyIconData类型的指针,也在ShellAPI单元中定义:(TNotifyIconData的定义很重要)

TNotifyIconData = TNotifyIconDataA;
TNotifyIconDataA = _NOTIFYICONDATAA;
type
_NOTIFYICONDATAA = record
    cbSize: DWORD;
    Wnd: HWND;  //窗口句柄
    uID: UINT;  //程序员定义的一个唯一标识符,如果一个应用程序有多个
//托盘图标,每个图标都 有唯一ID
    uFlags: UINT;  //指示后面的三个参数哪个有效
    uCallbackMessage: UINT;  //发向窗口whd的消息,消息的lparam
//参数和uID相同 lparam参数书鼠标经过图标时产生的消息。
    hIcon: HICON;  //图标句柄
    szTip: array [0..63] of AnsiChar;  //一个NUL结尾的字符串,当鼠标指向
//图标时会弹出提示框显示字符串
  end;

cbSize,整个记录的大小,初始化为SizeOf(TNotifyIconData);
uFlags ,  在ShellAPI单元中定义:

const
{$EXTERNALSYM NIF_MESSAGE}
  NIF_MESSAGE     = $00000001;
  {$EXTERNALSYM NIF_ICON}
  NIF_ICON        = $00000002;
  {$EXTERNALSYM NIF_TIP}
  NIF_TIP         = $00000004;

二、程序代码分析:
类声明:
TAppTrayIcon = class(TComponent)

2.1先看它的私有成员:
2.1.1数据成员和函数声明
  private
    { Private declarations }
    FNotiFicationHandle : HWnd;
    FTrayIcon : TIcon;
    FShowHint : Boolean;
  //提示文字
    FHint : String;
    FActive : Boolean;
  //当前是否激活状态
    FCurrentlyActive : Boolean;
  //双击事件
    FOnDblClick : TNotifyEvent;
  //自定义事件type  TRDownEvent = procedure (Sender: TObject;Pos:TPoint) of object;
    FOnRDown : TRDownEvent;
  //弹出菜单
    FPopupMenu: TPopupMenu;

    Procedure NotificationWndProc(Var Message : TMessage);
    Procedure SetShowHint(Const Value : Boolean);
    Procedure SetHint(const Value : String);
    Procedure SetTrayIcon(const Value : TIcon);
    Procedure SetActive(Const Value : Boolean);
    Procedure SetPopupMenu(const Value :TPopupMenu);
//    Procedure SetPopUpPos(Const Pos : TPoint);

2.1.2函数的定义
procedure TAppTrayIcon.NotificationWndProc(var Message: TMessage);
Var
  Pt:TPoint;
begin
  if Message.Msg = UWM_TRAYICON then   //注释 :<1><2>
  begin
    case Message.LParam of
      WM_LBUTTONDBLCLK:  //双击鼠标左键
        DoDblClick;      //执行双击事件,自定义
      WM_RBUTTONDOWN:    //按鼠标右键
      begin
        GetCursorPos(Pt);        //注释<3>
        if Assigned(FPopupMenu) then
        begin
          //RestoreApp;
          GetCursorPos(Pt);
          FPopupMenu.Popup(Pt.X ,Pt.Y);
        end;
        DoRDown(Pt);
      end;
    end;
  end;
end;
注释 :
<1>Message.Msg在Messages单元中定义
type
TMessage = packed record
    Msg: Cardinal;
    case Integer of
      0: (
        WParam: Longint;
        LParam: Longint;
        Result: Longint);
      1: (
        WParamLo: Word;
        WParamHi: Word;
        LParamLo: Word;
        LParamHi: Word;
        ResultLo: Word;
        ResultHi: Word);
  end;
<2>UWM_TRAYICON在本单元定义的常量:
const
ID_TRAYICON = 1;
UWM_TRAYICON = WM_USER + 1;
<3>GetCursorPos(Pt)在help中
BOOL GetCursorPos(

    LPPOINT lpPoint // address of structure for cursor position 
   );


procedure TAppTrayIcon.SetActive(const Value: Boolean);
begin
  FActive := Value; 
  if FActive then   //如果是激活状态,显示托盘图标
    ShowTrayIcon
  else
    RemoveTrayIcon;  //否则删除托盘图标
end;

procedure TAppTrayIcon.SetHint(const Value: String);
begin
  FHint := Value;
  SendTrayMessage(NIM_MODIFY);  //发送修改图标的消息
end;

procedure TAppTrayIcon.SetPopupMenu(const Value: TPopupMenu);
begin
  FPopupMenu := Value;
end;

procedure TAppTrayIcon.SetShowHint(const Value: Boolean);
begin
  FShowHint := Value;
  SendTrayMessage(NIM_MODIFY);
end;

procedure TAppTrayIcon.SetTrayIcon(const Value: TIcon);
begin
  FTrayIcon.Assign(Value);   //注释<4>
  SendTrayMessage(NIM_MODIFY);
end;

<4>Assign在Graphics单元里
procedure TIcon.Assign(Source: TPersistent);
begin
  if (Source = nil) or (Source is TIcon) then
  begin
    if Source <> nil then
    begin
      TIcon(Source).FImage.Reference;
      FImage.Release;
      FImage := TIcon(Source).FImage;
    end else
      NewImage(0, nil);
    Changed(Self);
    Exit;
  end;
  inherited Assign(Source);
end;
procedure TPersistent.Assign(Source: TPersistent);
begin
  if Source <> nil then Source.AssignTo(Self) else AssignError(nil);
end;

2.2 保护成员
2.2.1函数声明
protected
    { Protected declarations }
    Procedure DoDblClick;     //双图标标事件
    Procedure DoRDown(pos:TPoint);     //右击图标事件
    Procedure Loaded;override;     //  重新载入图标过程,是对父类虚拟函数的复写
    Procedure OnAppMinimize(Sender : TObject);    //
     //发送消息给api函数Shell_NotifyIcon()
    Function SendTrayMessage(AMessage:DWORD):Boolean; 

2.2.2实现部分
procedure TAppTrayIcon.DoDblClick;
begin
  if Assigned(OnDBlClick)then
    OnDblClick(Self);
end;

procedure TAppTrayIcon.DoRDown(pos:TPoint);
begin
  if Assigned(Onrdown)then
    OnRDown(Self,pos);
end;

procedure TAppTrayIcon.Loaded;
begin
  inherited Loaded;
  if not (csDesigning in ComponentState) then   //注释<5>
  begin
    if FTrayIcon.Handle = 0 then
      FTrayIcon.Assign(Application.Icon)
  end;

  SetTrayIcon(FTrayIcon);

  if FActive then
    ShowTrayIcon;
end;

<5> ComponentState
TComponent.ComponentState
Describes the current state of the component, indicating when a component needs to avoid certain actions.
type TComponentState = set of (csLoading, csReading, csWriting, csDestroying, csDesigning, csAncestor, csUpdating, csFixups, csFreeNotification, csInline, csDesignInstance);
property ComponentState: TComponentState;
csDesigning  The component is in a form being manipulated by the form designer.

procedure TAppTrayIcon.OnAppMinimize(Sender: TObject);
begin
  if FCurrentlyActive then
    RemoveFromTaskBar;
end;

function TAppTrayIcon.SendTrayMessage(AMessage: DWORD): Boolean;
Var
  Flags : Integer;
  NotifyIconData : TNotifyIconData;
begin
  Result := True;
  if csDesigning in ComponentState then
    exit;
  Flags := NIF_MESSAGE or NIF_ICON;
  if FShowHint then
    Flags := Flags or NIF_TIP;
  FillChar(NOtifyIconData,Sizeof(NotifyIconData),0);
  with NotifyIconData do
  begin
    cbSize := sizeof(TNotifyIconData);
    Wnd := FNotificationHandle;
    uID := ID_TRAYICON;
    uFlags := Flags;
    uCallBackMessage := UWM_TRAYICON;
    hIcon := FTrayIcon.Handle;
    StrLCopy(szTip,PChar(FHint),Sizeof(szTip));
  end;
  Result := Shell_NotifyIcon(AMessage,@NotifyIconData);  
end;
2.3公共成员
2.3.1声明部分
public
    { Public declarations }
    Constructor Create(AOwner : TComponent);Override;
    Destructor Destroy;override;
    Procedure RemoveTrayIcon;  //移除托盘图标
    Procedure RestoreApp;            //重新载入应用程序
    Procedure ShowTrayIcon;        //显示托盘图标
    Procedure RemoveFromTaskBar;   // 从任务栏移除
    Procedure ShowInTaskBar;       // 在任务栏显示

2.3.2实现部分

constructor TAppTrayIcon.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FNotificationHandle := AllocateHWnd(NotificationWndProc);   //<6>
  FTrayIcon := TIcon.Create;
  Application.OnMinimize := OnAppMinimize;    //<7>
end;

<6>:AllocateHWnd()
AllocateHWnd function
Creates a window that implements a specified window procedure.
function AllocateHWnd(Method: TWndMethod): HWND;
Description
Call AllocateHWnd to create a window that is not associated with a windowed control. Typically, this method is used to create non-visual windows that respond to messages but that do not appear in the user interface. For example, the TTimer component uses this method to create a window that responds to timer messages from Windows.
The Method parameter specifies the window procedure that the generated window uses to respond to messages.
AllocateHWnd returns the handle of the newly created window.
Note: Use the DeallocateHWnd procedure to free windows that are created using AllocateHWnd.
<7>:Application.OnMinimize
TApplication.OnMinimize
Occurs when an application is minimized.
property OnMinimize: TNotifyEvent;

destructor TAppTrayIcon.Destroy;
begin
  if FCurrentlyActive then
    RemoveTrayIcon;

  FTrayIcon.Free;

  if FNotificationHandle <> 0 then
    DeallocateHWnd(FNotificationHandle);
  inherited Destroy;
end;

procedure TAppTrayIcon.RemoveFromTaskBar;
begin
  if not(csDesigning in ComponentState) then
  begin
    SendTrayMessage(NIM_ADD);
    ShowWindow(Application.Handle,SW_HIDE);     //<8>
    ShowWindow(Application.MainForm.Handle,SW_HIDE);
  end;
end;
<8>:ShowWindow(),SW_HIDE
ShowWindow 
The ShowWindow function sets the specified window's show state.
BOOL ShowWindow(
    HWND hWnd, // handle of window
    int nCmdShow  // show state of window
   ); 
SW_HIDE Hides the window and activates another window.
procedure TAppTrayIcon.RemoveTrayIcon;
begin
  if FCurrentlyActive then
    if SendTrayMessage(NIM_DELETE) then
    begin
      FCurrentlyActive := False;
      ShowInTaskBar;
    end;
end;

procedure TAppTrayIcon.RestoreApp;
var
  wnd: HWND;
  child: HWND;
begin
  ShowInTaskBar;
  Application.MainForm.Visible := True;
  child := Application.MainForm.Handle;
  wnd := child;
  while child <> 0 do
  begin
    wnd := child;
    child := GetTopWindow(wnd);    //<9>
  end;
  SetForeGroundWindow(wnd);      //<10>
  BringWindowToTop(wnd);         //<11>
  Application.BringToFront;          //<12>
  SetFocus(Application.MainForm.Handle);
end;
<9>:GetTopWindow
GetTopWindow 
The GetTopWindow function examines the Z order of the child windows associated with the specified parent window and retrieves the handle of the child window at the top of the Z order.
HWND GetTopWindow(
    HWND hWnd  // handle of parent window
   ); 
Parameters
hWnd
Identifies the parent window whose child windows are to be examined. If this parameter is NULL, the function returns a handle of the window at the top of the Z order.
Return Values
If the function succeeds, the return value is the handle of the child window at the top of the Z order. If the specified window has no child windows, the return value is NULL. To get extended error information, use the GetLastError function.
<10>:SetForeGroundWindow
The SetForegroundWindow function puts the thread that created the specified window into the foreground and activates the window. Keyboard input is directed to the window, and various visual cues are changed for the user.
<11>:BringWindowToTop
The BringWindowToTop function brings the specified window to the top of the Z order. If the window is a top-level window, it is activated. If the window is a child window, the top-level parent window associated with the child window is activated. <12>:Application.BringToFront
Sets the last active window as the topmost window on the desktop above all other applications.

procedure TAppTrayIcon.ShowInTaskBar;
begin
  if Not(csDesigning in ComponentState) then
  begin
    if Application.MainForm <> nil then
      ShowWindow(Application.MainForm.Handle,SW_SHOWNORMAL);
//   ShowWindow(Application.Handle,SW_RESTORE);
    ShowWindow(Application.Handle,SW_SHOWNORMAL);
  end;
end;

procedure TAppTrayIcon.ShowTrayIcon;
begin
  if SendTrayMessage(NIM_ADD) then
    FCurrentlyActive := True;
end;

published
    { Published declarations }
    Property Active : Boolean read FActive write SetActive;
    Property Hint : String read FHint write SetHint;
    Property OnDblClick : TNotifyEvent read FOnDblClick write FOnDblClick;
    Property PopUpMenu : TPopupMenu read FPopupMenu write SetPopupMenu;
    Property ShowHint : Boolean read FShowHint write SetShowHint;
    Property TrayIcon : TIcon read FTrayIcon write SetTrayIcon;
    Property OnRDown : TRDownEvent read FOnRDown write FOnRDown;
  end;
posted on 2007-04-13 21:44  左左右右  阅读(553)  评论(0编辑  收藏  举报