?? cooltray.pas
字號(hào):
unit CoolTray;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Menus, ShellApi, ExtCtrls;
const
{ Define user-defined message sent by the trayicon. We avoid low user-defined
messages that are used by Windows itself (eg. WM_USER+1 = DM_SETDEFID). }
WM_TRAYNOTIFY = WM_USER + 1024;
// Constant used for recreating trayicon on system traybar recover
IconID = 1;
// Constants used for balloon hint feature
WM_RESETTOOLTIP = WM_USER + 1025;
NIIF_NONE = $00000000;
NIIF_INFO = $00000001;
NIIF_WARNING = $00000002;
NIIF_ERROR = $00000003;
NIF_INFO = $00000010;
type
{ You can use the TNotifyIconData record structure defined in shellapi.pas.
However, WinME, Win2000, and WinXP have expanded this structure. We define
a similar structure, TNotifyIconDataEx. }
TNotifyIconDataEx = record
cbSize: DWORD;
Wnd: HWND;
uID: UINT;
uFlags: UINT;
uCallbackMessage: UINT;
hIcon: HICON;
// szTip: array[0..63] of AnsiChar;
szTip: array[0..127] of AnsiChar; // 0..63 of WideChar in stead?
dwState: DWORD;
dwStateMask: DWORD;
szInfo: array[0..255] of AnsiChar;
uTimeout: UINT; // union with uVersion: UINT;
szInfoTitle: array[0..63] of AnsiChar;
dwInfoFlags: DWORD;
end;
TBalloonHintIcon = (bitNone, bitInfo, bitWarning, bitError);
TBalloonHintTimeOut = 10..60; // Windows defines 10-60 secs. as min-max
TCycleEvent = procedure(Sender: TObject; NextIndex: Integer) of object;
TCoolTrayIcon = class(TComponent)
private
FIcon: TIcon;
FHint: String;
FShowHint: Boolean;
FPopupMenu: TPopupMenu;
FLeftPopup: Boolean;
FOnClick,
FOnDblClick: TNotifyEvent;
FOnMouseDown,
FOnMouseUp: TMouseEvent;
FOnMouseMove: TMouseMoveEvent;
FClickStart: Boolean;
CycleTimer: TTimer; // For icon cycling
FIconIndex: Integer; // Current index in imagelist
FIconList: TImageList;
FCycleIcons: Boolean;
FCycleInterval: Cardinal;
FWindowHandle: HWND; // Window handle (not general handle)
procedure SetCycleIcons(Value: Boolean);
procedure SetCycleInterval(Value: Cardinal);
procedure TimerCycle(Sender: TObject);
procedure HandleIconMessage(var Msg: TMessage);
function InitIcon: Boolean;
procedure SetIcon(Value: TIcon);
procedure SetIconList(Value: TImageList);
procedure SetIconIndex(Value: Integer);
procedure SetHint(Value: String);
procedure SetShowHint(Value: Boolean);
procedure PopupAtCursor;
protected
IconData: TNotifyIconDataEx; // Data of the tray icon wnd.
function HideIcon: Boolean;
procedure Click; dynamic;
procedure DblClick; 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;
procedure Notification(AComponent: TComponent; Operation: TOperation);
override;
function ShowIcon: Boolean;
function ModifyIcon: Boolean;
function RemoveIcon: Boolean;
public
property Handle: HWND read IconData.Wnd;
property WindowHandle: HWND read FWindowHandle;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function Refresh: Boolean;
function ShowBalloonHint(Title: String; Text: String; IconType: TBalloonHintIcon;
TimeoutSecs: TBalloonHintTimeOut): Boolean;
procedure Init;
published
// Properties:
property IconList: TImageList read FIconList write SetIconList;
property CycleIcons: Boolean read FCycleIcons write SetCycleIcons
default False;
property CycleInterval: Cardinal read FCycleInterval
write SetCycleInterval;
property Hint: String read FHint write SetHint;
property ShowHint: Boolean read FShowHint write SetShowHint
default True;
property Icon: TIcon read FIcon write SetIcon stored True;
property IconIndex: Integer read FIconIndex write SetIconIndex;
property PopupMenu: TPopupMenu read FPopupMenu write FPopupMenu;
property LeftPopup: Boolean read FLeftPopup write FLeftPopup
default False;
// Events:
property OnClick: TNotifyEvent read FOnClick write FOnClick;
property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
end;
procedure Register;
implementation
{--------------------- TCoolTrayIcon ----------------------}
constructor TCoolTrayIcon.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FShowHint := True; // Show hint by default
// SettingPreview := False;
FIcon := TIcon.Create;
IconData.cbSize := SizeOf(TNotifyIconDataEx);
// IconData.wnd points to procedure to receive callback messages from the icon
IconData.wnd := AllocateHWnd(HandleIconMessage);
// Add an id for the tray icon
IconData.uId := IconID;
// We want icon, message handling, and tooltips by default
IconData.uFlags := NIF_ICON + NIF_MESSAGE + NIF_TIP;
// Message to send to IconData.wnd when event occurs
IconData.uCallbackMessage := WM_TRAYNOTIFY;
FWindowHandle := GetWindowLong(IconData.wnd, GWL_HWNDPARENT);
CycleTimer := TTimer.Create(Self);
CycleTimer.Enabled := False;
CycleTimer.Interval := FCycleInterval;
CycleTimer.OnTimer := TimerCycle;
end;
destructor TCoolTrayIcon.Destroy;
begin
RemoveIcon; // Remove the icon from the tray
FIcon.Free; // Free the icon
DeallocateHWnd(IconData.Wnd); // Free the tray window
CycleTimer.Free;
inherited Destroy;
end;
procedure TCoolTrayIcon.Init;
begin
ModifyIcon;
ShowIcon;
end;
procedure TCoolTrayIcon.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
{ Check if either the imagelist or the popup menu is about
to be deleted }
if (AComponent = IconList) and (Operation = opRemove) then
begin
FIconList := nil;
IconList := nil;
end;
if (AComponent = PopupMenu) and (Operation = opRemove) then begin
FPopupMenu := nil;
PopupMenu := nil;
end;
end;
procedure TCoolTrayIcon.HandleIconMessage(var Msg: TMessage);
function ShiftState: TShiftState;
// Return the state of the shift, ctrl, and alt keys
begin
Result := [];
if GetAsyncKeyState(VK_SHIFT) < 0 then
Include(Result, ssShift);
if GetAsyncKeyState(VK_CONTROL) < 0 then
Include(Result, ssCtrl);
if GetAsyncKeyState(VK_MENU) < 0 then
Include(Result, ssAlt);
end;
var
Pt: TPoint;
Shift: TShiftState;
begin
if Msg.Msg = WM_TRAYNOTIFY then
// Take action if a message from the icon comes through
begin
case Msg.lParam of
WM_MOUSEMOVE: begin
Shift := ShiftState;
GetCursorPos(Pt);
MouseMove(Shift, Pt.X, Pt.Y);
end;
WM_LBUTTONDOWN:
begin
Shift := ShiftState + [ssLeft];
GetCursorPos(Pt);
MouseDown(mbLeft, Shift, Pt.X, Pt.Y);
FClickStart := True;
if FLeftPopup then
PopupAtCursor;
end;
WM_RBUTTONDOWN:
begin
Shift := ShiftState + [ssRight];
GetCursorPos(Pt);
MouseDown(mbRight, Shift, Pt.X, Pt.Y);
PopupAtCursor;
end;
WM_MBUTTONDOWN:
begin
Shift := ShiftState + [ssMiddle];
GetCursorPos(Pt);
MouseDown(mbMiddle, Shift, Pt.X, Pt.Y);
end;
WM_LBUTTONUP:
begin
Shift := ShiftState + [ssLeft];
GetCursorPos(Pt);
if FClickStart then // Then WM_LBUTTONDOWN was called before
begin
FClickStart := False;
Click; // We have a click
end;
MouseUp(mbLeft, Shift, Pt.X, Pt.Y);
end;
WM_RBUTTONUP:
begin
Shift := ShiftState + [ssRight];
GetCursorPos(Pt);
MouseUp(mbRight, Shift, Pt.X, Pt.Y);
end;
WM_MBUTTONUP:
begin
Shift := ShiftState + [ssMiddle];
GetCursorPos(Pt);
MouseUp(mbMiddle, Shift, Pt.X, Pt.Y);
end;
WM_LBUTTONDBLCLK:
DblClick;
end;
end
else // Messages that didn't go through the icon
case Msg.Msg of
{ Windows sends us a WM_QUERYENDSESSION message when it prepares
for shutdown. Msg.Result must not return 0, or the system will
be unable to shut down. }
WM_QUERYENDSESSION: begin
//showmessage('WM_QUERYENDSESSION');
// PostQuitMessage(0);
Msg.Result := 1;
end;
{
WM_DESTROY: begin
showmessage('WM_DESTROY');
PostQuitMessage(0);
Msg.Result := 0;
end;
}
{
WM_ENDSESSION: begin
//showmessage('WM_ENDSESSION');
Msg.Result := 0;
end;
}
else // Handle all other messages with the default handler
Msg.Result := DefWindowProc(IconData.Wnd, Msg.Msg, Msg.wParam, Msg.lParam);
end;
end;
procedure TCoolTrayIcon.SetIcon(Value: TIcon);
begin
FIcon.Assign(Value);
ModifyIcon;
end;
procedure TCoolTrayIcon.SetCycleIcons(Value: Boolean);
begin
FCycleIcons := Value;
if Value then
SetIconIndex(0);
CycleTimer.Enabled := Value;
end;
procedure TCoolTrayIcon.SetCycleInterval(Value: Cardinal);
begin
FCycleInterval := Value;
CycleTimer.Interval := FCycleInterval;
end;
procedure TCoolTrayIcon.SetIconList(Value: TImageList);
begin
FIconList := Value;
{
// Set CycleIcons = false if IconList is nil
if Value = nil then
SetCycleIcons(False);
}
SetIconIndex(0);
end;
procedure TCoolTrayIcon.SetIconIndex(Value: Integer);
begin
if FIconList <> nil then
begin
FIconIndex := Value;
if Value >= FIconList.Count then
FIconIndex := FIconList.Count -1;
FIconList.GetIcon(FIconIndex, FIcon);
end else
FIconIndex := 0;
ModifyIcon;
end;
procedure TCoolTrayIcon.SetHint(Value: String);
begin
FHint := Value;
ModifyIcon;
end;
procedure TCoolTrayIcon.SetShowHint(Value: Boolean);
begin
FShowHint := Value;
ModifyIcon;
end;
function TCoolTrayIcon.InitIcon: Boolean;
// Set icon and tooltip
begin
IconData.hIcon := FIcon.Handle;
if (FHint <> '') and (FShowHint) then
StrLCopy(IconData.szTip, PChar(FHint), SizeOf(IconData.szTip)-1)
// StrLCopy must be used since szTip is only 64 bytes
else
IconData.szTip := '';
Result := True;
end;
function TCoolTrayIcon.ShowIcon: Boolean;
// Add/show the icon on the tray
begin
Result := InitIcon;
if Result then
Result := Shell_NotifyIcon(NIM_ADD, @IconData);
end;
function TCoolTrayIcon.HideIcon: Boolean;
// Remove/hide the icon from the tray
begin
Result := InitIcon;
if Result then
Result := RemoveIcon;
end;
function TCoolTrayIcon.ModifyIcon: Boolean;
// Change icon or tooltip if icon already placed
begin
Result := False;
if InitIcon then
Result := Shell_NotifyIcon(NIM_MODIFY, @IconData);
end;
procedure TCoolTrayIcon.TimerCycle(Sender: TObject);
begin
if Assigned(FIconList) then begin
FIconList.GetIcon(FIconIndex, FIcon);
if FIconIndex < FIconList.Count-1 then
SetIconIndex(FIconIndex+1)
else
SetIconIndex(0);
end;
end;
function TCoolTrayIcon.ShowBalloonHint(Title: String; Text: String;
IconType: TBalloonHintIcon; TimeoutSecs: TBalloonHintTimeOut): Boolean;
// Show balloon hint. Return false if error.
const
aBalloonIconTypes: array[TBalloonHintIcon] of Byte =
(NIIF_NONE, NIIF_INFO, NIIF_WARNING, NIIF_ERROR);
begin
with IconData do begin
uFlags := uFlags or NIF_INFO;
StrPCopy(szInfo, '');
end;
ModifyIcon;
// Display new balloon hint
with IconData do begin
uFlags := uFlags or NIF_INFO;
StrPCopy(szInfo, Text);
StrPCopy(szInfoTitle, Title);
uTimeout := TimeoutSecs * 1000;
dwInfoFlags := aBalloonIconTypes[IconType];
end;
Result := ModifyIcon;
{ Remove NIF_INFO before next call to ModifyIcon (or else the balloon hint
will redisplay itself) }
with IconData do
uFlags := NIF_ICON + NIF_MESSAGE + NIF_TIP;
end;
function TCoolTrayIcon.Refresh: Boolean;
// Refresh the icon
begin
Result := ModifyIcon;
end;
procedure TCoolTrayIcon.PopupAtCursor;
var
CursorPos: TPoint;
begin
if Assigned(PopupMenu) and PopupMenu.AutoPopup then
if GetCursorPos(CursorPos) then
begin
{ Win98 (but not Win95/WinNT) seems to empty a popup menu before
closing it. This is a problem when the menu is about to display
while it already is active (two click-events in succession). The
menu will flicker annoyingly. Calling ProcessMessages fixes this. }
Application.ProcessMessages;
{ Bring the main form or its modal dialog to the foreground.
This also ensures the popup menu closes after it loses focus. }
SetForegroundWindow((Owner as TWinControl).Handle);
{
This seems unnecessary(?):
if Screen.ActiveControl <> nil then
if (Screen.ActiveControl.Owner is TWinControl) then
SetForegroundWindow((Screen.ActiveControl.Owner as TWinControl).Handle);
}
// Now make the menu pop up
PopupMenu.PopupComponent := Self;
PopupMenu.Popup(CursorPos.X, CursorPos.Y);
// Post an empty message to make the popup menu disappear
PostMessage((Owner as TWinControl).Handle, WM_NULL, 0, 0);
end;
end;
procedure TCoolTrayIcon.Click;
begin
// Execute user-assigned method
if Assigned(FOnClick) then
FOnClick(Self);
end;
procedure TCoolTrayIcon.DblClick;
begin
// Execute user-assigned method
if Assigned(FOnDblClick) then
FOnDblClick(Self);
end;
procedure TCoolTrayIcon.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
// Execute user-assigned method
if Assigned(FOnMouseDown) then
FOnMouseDown(Self, Button, Shift, X, Y);
end;
procedure TCoolTrayIcon.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
// Execute user-assigned method
if Assigned(FOnMouseUp) then
FOnMouseUp(Self, Button, Shift, X, Y);
end;
procedure TCoolTrayIcon.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
// Execute user-assigned method
if Assigned(FOnMouseMove) then
FOnMouseMove(Self, Shift, X, Y);
end;
function TCoolTrayIcon.RemoveIcon: Boolean;
begin
Result := Shell_NotifyIcon(NIM_DELETE, @IconData);
end;
procedure Register;
begin
RegisterComponents('Custom', [TCoolTrayIcon]);
end;
end.
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -