Главная » Delphi » Сокрытие приложения

0

Еще одним  аспектом приложений, связанных с областью индикаторов панели  за дач, является то, что они не отображаются на панели  задач в виде кнопок. Чтобы обеспечить приложение подобной возможностью, в компонент TTrayNotifyIcon введено свойство HideTask, позволяющее пользователю самому решить, отображать или  нет  приложение на панели задач  в виде  кнопки. Код  метода  write для такого свойства приведен ниже.  Главную роль  здесь  играет строка, содержащая вызов  про цедуры API Win32 ShowWindow(), которой передается свойство Handle объекта Ap- plication, а также константа, определяющая, будет ли приложение отображаться на панели  задач в виде кнопки.

procedure TTrayNotifyIcon.SetHideTask(Value: Boolean);

{ Метод Write для свойства HideTask. }

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;В листинге 16.1 приведен код модуля TrayIcon.pas, представляющего собой реа

лизацию компонента TTrayNotifyIcon.

Листинг 16.1. TrayIcon.pas — исходный  код компонента TTrayNotifyIcon

unit TrayIcon;

interface

uses Windows, SysUtils, Messages, ShellAPI, Classes, Graphics, Forms, 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 FPopupMenuwrite SetPopupMenu;

property OnClick: TNotifyEvent read FOnClick write FOnClick;

property OnDblClick: TNotifyEvent read FOnDblClick

write FOnDblClick;

end;

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 := Classes.AllocateHWnd(TrayWndProc);

end;

destructor TIconManager.Destroy;

begin

if FHWindow <> 0 then Classes.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

{ Запустить таймер при первом щелчке мышью.

Событие OnClick будет передано методом OnTimer,

гарантируя, что двойного щелчка не было. }

WM_LBUTTONDOWN: TheIcon.FTimer.Enabled := True;{ Сбросить флаг двойного щелчка. Это предотвратит одиночный щелчок. }

WM_LBUTTONDBLCLK: begin

TheIcon.FNoShowClick := True;

if Assigned(TheIcon.FOnDblClick) then

TheIcon.FOnDblClick(Self);

end;

WM_RBUTTONDOWN: begin

if Assigned(TheIcon.FPopupMenu) then begin

{ Вызвать функцию SetForegroundWindow, необходимую API }

SetForegroundWindow(IconMgr.HWindow);

{ Открыть контекстное меню в позиции курсора. }

GetCursorPos(Pt);

TheIcon.FPopupMenu.Popup(Pt.X, Pt.Y);

{ Отправить сообщение, необходимое API для

переключения задач. }

PostMessage(IconMgr.HWindow, WM_USER, 0, 0);

end;

end;

end;

end

else

{ Если сообщение не относится к панели задач, то вызвать

процедуру 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;

{ Загрузить стандартную пиктограмму окна… }

LoadDefaultIcon;

end;

destructor TTrayNotifyIcon.Destroy;

begin

// Удалить пиктограмму

if FIconVisible then SetIconVisible(False);

FIcon.Free;                                  // Освободить ресурс

FTimer.Free;

inherited Destroy;

end;function TTrayNotifyIcon.ActiveIconHandle: THandle;

{ Возвращает дескриптор активного индикатора. }

begin

{ Если ни одна из пиктограмм не загружена, возвратить

стандартную пиктограмму. }

if (FIcon.Handle <> 0) then

Result := FIcon.Handle

else

Result := FDefaultIcon;

end;

procedure TTrayNotifyIcon.LoadDefaultIcon;

{ Загружает стандартную пиктограмму окна, которая всегда "под

рукой". Это позволит компоненту использовать логотип Windows в

качестве стандартной пиктограммы, если в свойстве Icon не выбрана

ни одна из пиктограмм. }

begin

FDefaultIcon := LoadIcon(0, IDI_WINLOGO);

end;

procedure TTrayNotifyIcon.Loaded;

{ Вызывается после загрузки компонента из потока. }

begin

inherited Loaded;

{ Если предполагается, что пиктограмма видима, создать ее. }

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);

{ Таймер используется для отслеживания времени между двумя щелчками

двойного щелчка. Реакция на первый щелчок задерживается на время,

достаточное для того, чтобы удостовериться в отсутствии второго

щелчка. Смысл всех этих манипуляций состоит лишь в одном:

обеспечить независимость событий OnClicks и OnDblClicks. }

begin

{ Отключить таймер, ведь он нужен только при первом щелчке. }

FTimer.Enabled := False;

{ Если второго щелчка так и не последовало, то передать

одиночный щелчок. }

if (not FNoShowClick) and Assigned(FOnClick) then

FOnClick(Self);

FNoShowClick := False;       // Сбросить флаг

end;procedure TTrayNotifyIcon.SendTrayMessage(Msg: DWORD; Flags: UINT);

{ Этот метод содержит вызов функции API Shell_NotifyIcon. }

begin

{ Заполнить поля записи соответствующими значениями. }

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);

{ Метод Write для свойства HideTask. }

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 для свойства Icon. }

begin

FIcon.Assign(Value);      // Установить новую пиктограмму

{ Изменить индикатор на панели задач. }

if FIconVisible then SendTrayMessage(NIM_MODIFY, NIF_ICON);

end;

procedure TTrayNotifyIcon.SetIconVisible(Value: Boolean);

{ Метод записи для свойства IconVisible }

const{ Флаги, для добавления или удаления индикатора панели задач } MsgArray: array[Boolean] of DWORD = (NIM_DELETE, NIM_ADD);

begin

if FIconVisible <> Value then begin

FIconVisible := Value;

{ Установить соответствующий индикатор. }

SendTrayMessage(MsgArray[Value],

NIF_MESSAGE or NIF_ICON or NIF_TIP);

end;

end;

procedure TTrayNotifyIcon.SetPopupMenu(Value: TPopupMenu);

{ Метод записи для свойства PopupMenu }

begin

FPopupMenu := Value;

if Value <> nil then Value.FreeNotification(Self);

end;

const

{ Строка для идентификации зарегистрированного

сообщения Windows. }

TrayMsgStr = ‘DDG.TrayNotifyIconMsg';

initialization

{ Получить уникальный идентификатор сообщения Windows

для обратного вызова из панели задач. }

DDGM_TRAYICON := RegisterWindowMessage(TrayMsgStr);

IconMgr := TIconManager.Create;

finalization

IconMgr.Free;

end.На рис. 16.2 показан внешний вид индикатора, созданного на панели задач компо

нентом TTrayNotifyIcon.

Рис. 16.2. Компонент TTrayNotifyIcon в действии

Кстати, так как индикатор инициализируется внутри  конструктора компонента, а конструкторы выполняются и во время  разработки, то компонент отображает пред назначенную для индикатора пиктограмму даже во время  разработки приложения!

Пример приложения

Чтобы лучше ознакомиться с компонентом TTrayNotifyIcon, рассмотрим его работу  в контексте приложения. На  рис. 16.3 изображено главное окно,  а в листин ге 16.2 — код главного модуля этого приложения.

Рис. 16.3. Приложение индикатора панели задач

Листинг 16.2. Main.pas — главный модуль приложения индикатора

unit main;

interface uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, ShellAPI, TrayIcon, Menus, ComCtrls;

type

TMainForm = class(TForm)

pmiPopup: TPopupMenu;

pgclPageCtl: TPageControl;

TabSheet1: TTabSheet;

btnClose: TButton;

btnTerm: TButton;

Terminate1: TMenuItem;

Label1: TLabel;

N1: TMenuItem;

Propeties1: TMenuItem;

TrayNotifyIcon1: TTrayNotifyIcon;

procedure NotifyIcon1Click(Sender: TObject);

procedure NotifyIcon1DblClick(Sender: TObject);

procedure FormClose(Sender: TObject;

var Action: TCloseAction);

procedure btnTermClick(Sender: TObject);

procedure btnCloseClick(Sender: TObject);

procedure FormCreate(Sender: TObject);

end;

var

MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TMainForm.NotifyIcon1Click(Sender: TObject);

begin

ShowMessage(‘Single click’);

end;

procedure TMainForm.NotifyIcon1DblClick(Sender: TObject);

begin

Show;

end;

procedure TMainForm.FormClose(Sender: TObject;

var Action: TCloseAction);

begin

Action := caNone;

Hide;

end;

procedure TMainForm.btnTermClick(Sender: TObject);

begin

Application.Terminate;

end;

procedure TMainForm.btnCloseClick(Sender: TObject);

begin

Hide;

end;

procedure TMainForm.FormCreate(Sender: TObject);

begin

TrayNotifyIcon1.IconVisible := True;

end;

end.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии