在编写一个托盘程序中,往往需要创建、修改、移除托盘图标,从这里开始入手。
一、创建、修改、移除托盘图标,只需调用一个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;
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.
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;
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;
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.
<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.
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.
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.
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.
);
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;