📄 trayicon.pas
字号:
unit TrayIcon;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ShellAPI, Menus, StdCtrls, ExtCtrls;type ENotifyIconError = class(Exception); TTrayNotifyIcon = class(TComponent) private FDefaultIcon: THandle; FIcon: TIcon; FHideTask: Boolean; FHint: string; FIconVisible: Boolean; FPopupMenu: TPopupMenu; FOnClick: TNotifyEvent; FOnDblClick: TNotifyEvent; FNoShowClick: Boolean; FTimer: TTimer; Tnd: TNotifyIconData; procedure SetIcon(Value: TIcon); procedure SetHideTask(Value: Boolean); procedure SetHint(Value: string); procedure SetIconVisible(Value: Boolean); procedure SetPopupMenu(Value: TPopupMenu); procedure SendTrayMessage(Msg: DWORD; Flags: UINT); function ActiveIconHandle: THandle; procedure OnButtonTimer(Sender: TObject); protected procedure Loaded; override; procedure LoadDefaultIcon; virtual; procedure Notification(AComponent: TComponent; Operation: TOperation); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property Icon: TIcon read FIcon write SetIcon; property HideTask: Boolean read FHideTask write SetHideTask default False; property Hint: String read FHint write SetHint; property IconVisible: Boolean read FIconVisible write SetIconVisible default False; property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu; property OnClick: TNotifyEvent read FOnClick write FOnClick; property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick; end;procedure Register;implementation{ TIconManager }{ 创建一个隐藏的窗口用于处理事务 }type TIconManager = class private FHWindow: HWnd; procedure TrayWndProc(var Message: TMessage); public constructor Create; destructor Destroy; override; property HWindow: HWnd read FHWindow write FHWindow; end;var IconMgr: TIconManager; DDGM_TRAYICON: Cardinal;constructor TIconManager.Create;begin FHWindow := AllocateHWnd(TrayWndProc);end;destructor TIconManager.Destroy;begin if FHWindow <> 0 then DeallocateHWnd(FHWindow); inherited Destroy;end;procedure TIconManager.TrayWndProc(var Message: TMessage);{ 此进程用于处理所有托盘图表返回的消息 }var Pt: TPoint; TheIcon: TTrayNotifyIcon;begin with Message do begin { 如果是托盘图表返回的消息 } if (Msg = DDGM_TRAYICON) then begin TheIcon := TTrayNotifyIcon(WParam); case lParam of { enable timer on first mouse down. } { OnClick will be fired by OnTimer method, provided } { double click has not occurred. } WM_LBUTTONDOWN: TheIcon.FTimer.Enabled := True; { Set no click flag on double click. This will supress } { the single click. } WM_LBUTTONDBLCLK: begin TheIcon.FNoShowClick := True; if Assigned(TheIcon.FOnDblClick) then TheIcon.FOnDblClick(Self); end; WM_RBUTTONDOWN: begin if Assigned(TheIcon.FPopupMenu) then begin { Call to SetForegroundWindow is required by API } SetForegroundWindow(IconMgr.HWindow); { Popup local menu at the cursor position. } GetCursorPos(Pt); TheIcon.FPopupMenu.Popup(Pt.X, Pt.Y); { Message post required by API to force task switch } PostMessage(IconMgr.HWindow, WM_USER, 0, 0); end; end; end; end else { If it isn't a tray callback message, then call DefWindowProc } Result := DefWindowProc(FHWindow, Msg, wParam, lParam); end;end;{ TTrayNotifyIcon }constructor TTrayNotifyIcon.Create(AOwner: TComponent);begin inherited Create(AOwner); FIcon := TIcon.Create; FTimer := TTimer.Create(Self); with FTimer do begin Enabled := False; Interval := GetDoubleClickTime; OnTimer := OnButtonTimer; end; { Keep default windows icon handy... } LoadDefaultIcon;end;destructor TTrayNotifyIcon.Destroy;begin if FIconVisible then SetIconVisible(False); // destroy icon FIcon.Free; // free stuff FTimer.Free; inherited Destroy;end;function TTrayNotifyIcon.ActiveIconHandle: THandle;{ Returns handle of active icon }begin { If no icon is loaded, then return default icon } if (FIcon.Handle <> 0) then Result := FIcon.Handle else Result := FDefaultIcon;end;procedure TTrayNotifyIcon.LoadDefaultIcon;{ Loads default window icon to keep it handy. }{ This will allow the component to use the windows logo }{ icon as the default when no icon is selected in the }{ Icon property. }begin FDefaultIcon := LoadIcon(0, IDI_WINLOGO);end;procedure TTrayNotifyIcon.Loaded;{ Called after component is loaded from stream }begin inherited Loaded; { if icon is supposed to be visible, create it. } if FIconVisible then SendTrayMessage(NIM_ADD, NIF_MESSAGE or NIF_ICON or NIF_TIP);end;procedure TTrayNotifyIcon.Notification(AComponent: TComponent; Operation: TOperation);begin inherited Notification(AComponent, Operation); if (Operation = opRemove) and (AComponent = PopupMenu) then PopupMenu := nil;end;procedure TTrayNotifyIcon.OnButtonTimer(Sender: TObject);{ Timer used to keep track of time between two clicks of a }{ double click. This delays the first click long enough to }{ ensure that a double click hasn't occurred. The whole }{ point of these gymnastics is to allow the component to }{ receive OnClicks and OnDblClicks independently. }begin { Disable timer because we only want it to fire once. } FTimer.Enabled := False; { if double click has not occurred, then fire single click. } if (not FNoShowClick) and Assigned(FOnClick) then FOnClick(Self); FNoShowClick := False; // reset flagend;procedure TTrayNotifyIcon.SendTrayMessage(Msg: DWORD; Flags: UINT);{ This method wraps up the call to the API's Shell_NotifyIcon }begin { Fill up record with appropriate values } with Tnd do begin cbSize := SizeOf(Tnd); StrPLCopy(szTip, PChar(FHint), SizeOf(szTip)); uFlags := Flags; uID := UINT(Self); Wnd := IconMgr.HWindow; uCallbackMessage := DDGM_TRAYICON; hIcon := ActiveIconHandle; end; Shell_NotifyIcon(Msg, @Tnd);end;procedure TTrayNotifyIcon.SetHideTask(Value: Boolean);{ 修改是否在任务栏显示属性 }const { 设置标志,用于确定任务栏显示状态 } ShowArray: array[Boolean] of integer = (sw_ShowNormal, sw_Hide);begin if FHideTask <> Value then begin FHideTask := Value; { 在设计期不做任何修改 } if not (csDesigning in ComponentState) then ShowWindow(Application.Handle, ShowArray[FHideTask]); end;end;procedure TTrayNotifyIcon.SetHint(Value: string);{ 设置Hint属性 }begin if FHint <> Value then begin FHint := Value; if FIconVisible then {修改图标的提示信息} SendTrayMessage(NIM_MODIFY, NIF_TIP); end;end;procedure TTrayNotifyIcon.SetIcon(Value: TIcon);{ Write method for Icon property. }begin FIcon.Assign(Value); // set new icon { Change icon on notification tray } if FIconVisible then SendTrayMessage(NIM_MODIFY, NIF_ICON);end;procedure TTrayNotifyIcon.SetIconVisible(Value: Boolean);{ 修改是否在任务栏显示属性 }const { Flags to add or delete a tray notification icon } MsgArray: array[Boolean] of DWORD = (NIM_DELETE, NIM_ADD);begin if FIconVisible <> Value then begin FIconVisible := Value; { Set icon as appropriate } SendTrayMessage(MsgArray[Value], NIF_MESSAGE or NIF_ICON or NIF_TIP); end;end;procedure TTrayNotifyIcon.SetPopupMenu(Value: TPopupMenu);{ Write method for PopupMenu property }begin FPopupMenu := Value; if Value <> nil then Value.FreeNotification(Self);end;procedure Register;begin RegisterComponents('CYL', [TTrayNotifyIcon]);end;const { String to identify registered window message } TrayMsgStr = 'DDG.TrayNotifyIconMsg';initialization { Get a unique windows message ID for tray callback } DDGM_TRAYICON := RegisterWindowMessage(TrayMsgStr); IconMgr := TIconManager.Create;finalization IconMgr.Free;end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -