您的位置:首页 > 其它

一个支持FMX.Win框架的托盘控件

2016-08-27 02:59 337 查看
不多说了 直接上代码........有任何问题请给我邮件....

//  ***************************************************************************
//
//  FMX.Win 平台下托盘
//
//  版本: 1.0
//  作者: 堕落恶魔
//  修改日期: 2015-06-26
//  QQ: 17948876
//  E-mail: hs_kill_god@hotmail.com
//  博客: http://www.cnblogs.com/hs-kill/ //
//  !!! 若有修改,请通知作者,谢谢合作 !!!
//
//  ---------------------------------------------------------------------------
//
//  说明:
//    1.默认图标为程序图标
//    2.需要使用动态图标时, 要先传入一个动态图标句柄数组
//
//  ***************************************************************************

unit FMX.Win.TrayIcon;

interface

uses
Winapi.Windows, Winapi.Messages, Winapi.ShellApi,
System.SysUtils, System.Classes, System.UITypes,
FMX.Forms, FMX.Types, FMX.Platform.Win, FMX.MultiResBitmap, FMX.Menus;

const
WM_SYSTEM_TRAY_MESSAGE = WM_USER + $128;

type
TBalloonFlags = (bfNone = NIIF_NONE, bfInfo = NIIF_INFO,
bfWarning = NIIF_WARNING, bfError = NIIF_ERROR);

[RootDesignerSerializerAttribute('', '', False)]
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
TTrayIcon = class(TComponent)
private
class var
RM_TaskbarCreated: DWORD;
private
FAnimate: Boolean;
FBalloonHint: string;
FBalloonTitle: string;
FBalloonFlags: TBalloonFlags;
FIsClicked: Boolean;
FData: TNotifyIconData;
FIcon: HICON;
FCurrentIconIndex: UInt8;
FAnimateIconList: TArray<HICON>;
FPopupMenu: TPopupMenu;
FTimer: TTimer;
FHint: String;
FVisible: Boolean;
FOnBalloonClick: TNotifyEvent;
FOnClick: TNotifyEvent;
FOnDblClick: TNotifyEvent;
FOnMouseDown: TMouseEvent;
FOnMouseMove: TMouseMoveEvent;
FOnMouseUp: TMouseEvent;
FOnAnimate: TNotifyEvent;
FDefaultIcon: HICON;
function GetData: TNotifyIconData;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure SetHint(const Value: string);
function GetAnimateInterval: Cardinal;
procedure SetAnimateInterval(Value: Cardinal);
procedure SetAnimate(Value: Boolean);
procedure SetBalloonHint(const Value: string);
function GetBalloonTimeout: Integer;
procedure SetBalloonTimeout(Value: Integer);
procedure SetBalloonTitle(const Value: string);
procedure SetVisible(Value: Boolean); virtual;
procedure WindowProc(var Message: TMessage); virtual;
procedure DoOnAnimate(Sender: TObject); virtual;
property Data: TNotifyIconData read GetData;
function Refresh(Message: Integer): Boolean; overload;
public
constructor Create(Owner: TComponent); override;
destructor Destroy; override;
procedure Refresh; overload;
procedure SetDefaultIcon;
procedure ShowBalloonHint; virtual;
procedure SetAnimateIconList(AList: TArray<HICON>);
property DefaultIcon: HICON read FDefaultIcon write FDefaultIcon;
published
property Animate: Boolean read FAnimate write SetAnimate default False;
property AnimateInterval: Cardinal read GetAnimateInterval write SetAnimateInterval default 1000;
property Hint: string read FHint write SetHint;
property BalloonHint: string read FBalloonHint write SetBalloonHint;
property BalloonTitle: string read FBalloonTitle write SetBalloonTitle;
property BalloonTimeout: Integer read GetBalloonTimeout write SetBalloonTimeout default 10000;
property BalloonFlags: TBalloonFlags read FBalloonFlags write FBalloonFlags default bfNone;
property PopupMenu: TPopupMenu read FPopupMenu write FPopupMenu;
property Visible: Boolean read FVisible write SetVisible default False;
property OnBalloonClick: TNotifyEvent read FOnBalloonClick write FOnBalloonClick;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
property OnAnimate: TNotifyEvent read FOnAnimate write FOnAnimate;
end;

procedure Register;

implementation

{ TTrayIcon}

constructor TTrayIcon.Create(Owner: TComponent);
begin
inherited;
FAnimate := False;
FBalloonFlags := bfNone;
BalloonTimeout := 10000;
FTimer := TTimer.Create(nil);
FVisible := False;
FIsClicked := False;
FTimer.Enabled := False;
FTimer.OnTimer := DoOnAnimate;
FTimer.Interval := 1000;
SetLength(FAnimateIconList, 0);
FCurrentIconIndex := 0;
FDefaultIcon := LoadIcon(HInstance, PChar('MAINICON'));
FIcon := FDefaultIcon;

if not (csDesigning in ComponentState) then
begin
FData.cbSize := FData.SizeOf;
FData.Wnd := AllocateHwnd(WindowProc);
StrPLCopy(FData.szTip, Application.Title, Length(FData.szTip) - 1);
FData.uID := FData.Wnd;
FData.uTimeout := 10000;
FData.hIcon := FDefaultIcon;
FData.uFlags := NIF_ICON or NIF_MESSAGE;
FData.uCallbackMessage := WM_SYSTEM_TRAY_MESSAGE;
if Length(Application.Title) > 0 then
FData.uFlags := FData.uFlags or NIF_TIP;
Refresh;
end;
end;

destructor TTrayIcon.Destroy;
begin
if not (csDesigning in ComponentState) then
begin
Refresh(NIM_DELETE);
DeallocateHWnd(FData.Wnd);
end;
FTimer.Free;
inherited;
end;

procedure TTrayIcon.SetVisible(Value: Boolean);
begin
if FVisible <> Value then
begin
FVisible := Value;
if (not FAnimate) or (FAnimate and (Length(FAnimateIconList) = 0)) then
SetDefaultIcon;

if not (csDesigning in ComponentState) then
begin
if FVisible then
Refresh(NIM_ADD)
else if not (csLoading in ComponentState) then
begin
if not Refresh(NIM_DELETE) then
raise EOutOfResources.Create('Cannot remove shell notification icon');
end;
if FAnimate then
FTimer.Enabled := Value;
end;
end;
end;

procedure TTrayIcon.SetHint(const Value: string);
begin
if CompareStr(FHint, Value) <> 0 then
begin
FHint := Value;
StrPLCopy(FData.szTip, Hint, Length(FData.szTip) - 1);
if Length(Hint) > 0 then
FData.uFlags := FData.uFlags or NIF_TIP
else
FData.uFlags := FData.uFlags and not NIF_TIP;
Refresh;
end;
end;

function TTrayIcon.GetAnimateInterval: Cardinal;
begin
Result := FTimer.Interval;
end;

procedure TTrayIcon.SetAnimateIconList(AList: TArray<HICON>);
begin
Animate := False;
FAnimateIconList := AList;
end;

procedure TTrayIcon.SetAnimateInterval(Value: Cardinal);
begin
FTimer.Interval := Value;
end;

procedure TTrayIcon.SetAnimate(Value: Boolean);
begin
if FAnimate <> Value then
begin
FAnimate := Value;
if not (csDesigning in ComponentState) then
begin
if (Length(FAnimateIconList) > 0) and Visible then
FTimer.Enabled := Value;
if (not FAnimate) and (Length(FAnimateIconList) <> 0) then
FIcon := FAnimateIconList[FCurrentIconIndex];
end;
end;
end;

{ Message handler for the hidden shell notification window. Most messages
use WM_SYSTEM_TRAY_MESSAGE as the Message ID, with WParam as the ID of the
shell notify icon data. LParam is a message ID for the actual message, e.g.,
WM_MOUSEMOVE. Another important message is WM_ENDSESSION, telling the shell
notify icon to delete itself, so Windows can shut down.

Send the usual events for the mouse messages. Also interpolate the OnClick
event when the user clicks the left button, and popup the menu, if there is
one, for right click events. }

[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=True)]
procedure TTrayIcon.WindowProc(var Message: TMessage);

{ Return the state of the shift keys. }
function ShiftState: TShiftState;
begin
Result := [];
if GetKeyState(VK_SHIFT) < 0 then
Include(Result, ssShift);
if GetKeyState(VK_CONTROL) < 0 then
Include(Result, ssCtrl);
if GetKeyState(VK_MENU) < 0 then
Include(Result, ssAlt);
end;

var
Point: TPoint;
Shift: TShiftState;
begin
case Message.Msg of
WM_QUERYENDSESSION: Message.Result := 1;
WM_ENDSESSION:
if TWmEndSession(Message).EndSession then
Refresh(NIM_DELETE);
WM_SYSTEM_TRAY_MESSAGE:
begin
case Int64(Message.lParam) of
WM_MOUSEMOVE:
if Assigned(FOnMouseMove) then
begin
Shift := ShiftState;
GetCursorPos(Point);
FOnMouseMove(Self, Shift, Point.X, Point.Y);
end;
WM_LBUTTONDOWN:
begin
if Assigned(FOnMouseDown) then
begin
Shift := ShiftState + [ssLeft];
GetCursorPos(Point);
FOnMouseDown(Self, TMouseButton.mbLeft, Shift, Point.X, Point.Y);
end;
FIsClicked := True;
end;
WM_LBUTTONUP:
begin
Shift := ShiftState + [ssLeft];
GetCursorPos(Point);
if FIsClicked and Assigned(FOnClick) then
begin
FOnClick(Self);
FIsClicked := False;
end;
if Assigned(FOnMouseUp) then
FOnMouseUp(Self, TMouseButton.mbLeft, Shift, Point.X, Point.Y);
end;
WM_RBUTTONDOWN:
if Assigned(FOnMouseDown) then
begin
Shift := ShiftState + [ssRight];
GetCursorPos(Point);
FOnMouseDown(Self, TMouseButton.mbRight, Shift, Point.X, Point.Y);
end;
WM_RBUTTONUP:
begin
Shift := ShiftState + [ssRight];
GetCursorPos(Point);
if Assigned(FOnMouseUp) then
FOnMouseUp(Self, TMouseButton.mbRight, Shift, Point.X, Point.Y);
if Assigned(FPopupMenu) then
begin
SetForegroundWindow(FormToHWND(Application.MainForm));
Application.ProcessMessages;
FPopupMenu.PopupComponent := Owner;
FPopupMenu.Popup(Point.x, Point.y);
end;
end;
WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK:
if Assigned(FOnDblClick) then
FOnDblClick(Self);
WM_MBUTTONDOWN:
if Assigned(FOnMouseDown) then
begin
Shift := ShiftState + [ssMiddle];
GetCursorPos(Point);
FOnMouseDown(Self, TMouseButton.mbMiddle, Shift, Point.X, Point.Y);
end;
WM_MBUTTONUP:
if Assigned(FOnMouseUp) then
begin
Shift := ShiftState + [ssMiddle];
GetCursorPos(Point);
FOnMouseUp(Self, TMouseButton.mbMiddle, Shift, Point.X, Point.Y);
end;
NIN_BALLOONHIDE, NIN_BALLOONTIMEOUT:
FData.uFlags := FData.uFlags and not NIF_INFO;
NIN_BALLOONUSERCLICK:
if Assigned(FOnBalloonClick) then
FOnBalloonClick(Self);
end;
end;
else
if (Cardinal(Message.Msg) = RM_TaskBarCreated) and Visible then
Refresh(NIM_ADD);
end;
end;

procedure TTrayIcon.Refresh;
begin
if not (csDesigning in ComponentState) then
begin
FData.hIcon := FIcon;
if Visible then
Refresh(NIM_MODIFY);
end;
end;

function TTrayIcon.Refresh(Message: Integer): Boolean;
//var
//  SavedTimeout: Integer;
begin
Result := Shell_NotifyIcon(Message, @FData);
{  if Result then
begin
SavedTimeout := FData.uTimeout;
FData.uTimeout := 4;
Result := Shell_NotifyIcon(NIM_SETVERSION, FData);
FData.uTimeout := SavedTimeout;
end;}
end;

procedure TTrayIcon.DoOnAnimate(Sender: TObject);
var
nAnimateIconCount: UInt8;
begin
if Assigned(FOnAnimate) then
FOnAnimate(Self);
nAnimateIconCount := Length(FAnimateIconList);
if (nAnimateIconCount > 0) and (FCurrentIconIndex < nAnimateIconCount - 1) then
FCurrentIconIndex := FCurrentIconIndex + 1
else
FCurrentIconIndex := 0;
FIcon := FAnimateIconList[FCurrentIconIndex];
Refresh;
end;

procedure TTrayIcon.SetBalloonHint(const Value: string);
begin
if CompareStr(FBalloonHint, Value) <> 0 then
begin
FBalloonHint := Value;
StrPLCopy(FData.szInfo, FBalloonHint, Length(FData.szInfo) - 1);
Refresh(NIM_MODIFY);
end;
end;

procedure TTrayIcon.SetDefaultIcon;
begin
FIcon := FDefaultIcon;
Refresh;
end;

procedure TTrayIcon.SetBalloonTimeout(Value: Integer);
begin
FData.uTimeout := Value;
end;

function TTrayIcon.GetBalloonTimeout: Integer;
begin
Result := FData.uTimeout;
end;

function TTrayIcon.GetData: TNotifyIconData;
begin
Result := FData;
end;

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

procedure TTrayIcon.ShowBalloonHint;
begin
FData.uFlags := FData.uFlags or NIF_INFO;
FData.dwInfoFlags := Cardinal(FBalloonFlags);
Refresh(NIM_MODIFY);
end;

procedure TTrayIcon.SetBalloonTitle(const Value: string);
begin
if CompareStr(FBalloonTitle, Value) <> 0 then
begin
FBalloonTitle := Value;
StrPLCopy(FData.szInfoTitle, FBalloonTitle, Length(FData.szInfoTitle) - 1);
Refresh(NIM_MODIFY);
end;
end;

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

initialization
GroupDescendentsWith(TTrayIcon, FMX.Forms.TForm);

end.

http://www.cnblogs.com/hs-kill/p/4603012.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐