Главная » Delphi » Класс TAppBar: форма окна AppBar

0

Учитывая небольшие размеры функции API окна  AppBar,  ее нетрудно встроить в форму библиотеки VCL. В настоящем разделе речь  пойдет об инкапсуляции функции API AppBar  в элементе управления, производном от класса  TCustomForm. Поскольку компонент TCustomForm представляет собой  форму,  то и в окне  конструктора форм (Form Designer) работать с ним  будем как с формой верхнего уровня,  а не как с от дельным  компонентом в составе другой формы.

Большая  часть  работы в окне  AppBar  выполняется с помощью передачи оболочке Windows записи TAppBarData, что осуществляется благодаря вызову функции API SHAppBarMessage().  Компонент  TAppBar поддерживает  внутреннюю  запись TAppBarData по имени FABD. В конструкторе компонента и методе  CreateWnd() за пись  FABD настраивается на  вызов  функции SendAppBarMsg() для  создания окна AppBar. В частности, здесь инициализируется поле cbSize, поле uCallbackMessage получает значение, возвращаемое функцией API RegisterWindowMessage(), а поле hWnd получает дескриптор текущего  окна  формы. Функция  SendAppBarMessage() инкапсулирует функцию SHAppBarMessage() и определяется следующим образом:

function TAppBar.SendAppBarMsg(Msg: DWORD): UINT;

begin

Result := SHAppBarMessage(Msg, FABD);

end;

При  успешном  создании окна AppBar  вызывается метод SetAppBarEdge(), ис пользуемый для помещения окна  AppBar  в исходное положение. Этот  метод,  в свою очередь, вызывает метод  SetAppBarPos(), передавая флаг,  указывающий на требуе мую границу  экрана, у которой должно  разместиться окно  AppBar.  Флаги  ABE_TOP, ABE_BOTTOM,  ABE_LEFT и  ABE_RIGHT представляют  соответственно  верхнюю,  ниж нюю, левую и правую границы экрана. Реализация данного метода показана в приве

денном  ниже фрагменте кода:

procedure TAppBar.SetAppBarPos(Edge: UINT);

begin

if csDesigning in ComponentState then Exit;

FABD.uEdge := Edge;           // Установить границу окна

with FABD.rc do begin

// Установить координаты полного экрана

Top := 0;

Left := 0;

Right := Screen.Width;

Bottom := Screen.Height;

// Послать сообщение ABM_QUERYPOS для получения размеров

// соответствующего прямоугольника у границы экрана.

SendAppBarMsg(ABM_QUERYPOS);

// Перестроить прямоугольник на основании полученных данных

case Edge of

ABE_LEFT: Right := Left + FDockedWidth;

ABE_RIGHT: Left := Right – FDockedWidth;

ABE_TOP: Bottom := Top + FDockedHeight;

ABE_BOTTOM: Top := Bottom – FDockedHeight;

end;

// Установить позицию окна AppBar.

SendAppBarMsg(ABM_SETPOS);

end;

// Согласовать свойство BoundsRect с ограничивающим

// прямоугольником, передаваемым системе.

BoundsRect := FABD.rc;

end;

Сначала  в данном  методе  поле  uEdge записи FABD устанавливается равным значе нию параметра Edge. Затем поле rc заполняется значениями координат полного экрана и посылается сообщение ABM_QUERYPOS. Это  сообщение переустанавливает размеры прямоугольника, определяемого полем  rc, которое теперь содержит координаты пря моугольника, состыкованного с краем,  определяемым полем  uEdge. После  этого  поле rc перестраивается еще раз — до нужных  размеров подстраиваются высота  и ширина. Теперь поле  rc содержит окончательный  размер  ограничивающей рамки   для  окна AppBar. Затем  оболочке Windows посылается сообщение ABM_SETPOS, уведомляющее о создании нового прямоугольника, и, наконец, сам прямоугольник устанавливается с по мощью свойства BoundsRect элемента управления.

Как  уже упоминалось в настоящей главе,  уведомляющие сообщения  будут посы латься  окну, определяемому значением FABD.hWnd, с использованием идентификато ра сообщения, содержащегося в поле  FABD.uCallbackMessage. Уведомляющие со общения обрабатывает метод WndProc(), код которого приведен ниже.

procedure TAppBar.WndProc(var M: TMessage);

var

State: UINT;

WndPos: HWnd;

begin

if M.Msg = AppBarMsg then begincase M.WParam of

// Рассылается при изменении свойств "всегда наверху" или

// "автосокрытие".

ABN_STATECHANGE: begin

// Проверка флага ABS_ALWAYSONTOP ("всегда наверху")

State := SendAppBarMsg(ABM_GETSTATE);

if ABS_ALWAYSONTOP and State = 0 then

SetTopMost(False)

else

SetTopMost(True);

end;

// Запущено (или закрыто последнее) полноэкранное

// приложение.

ABN_FULLSCREENAPP: begin

// Установить обратный порядок сортировки окон AppBar.

State := SendAppBarMsg(ABM_GETSTATE);

if M.lParam <> 0 then begin

if ABS_ALWAYSONTOP and State = 0 then

SetTopMost(False)

else

SetTopMost(True);

end else

if State and ABS_ALWAYSONTOP <> 0 then

SetTopMost(True);

end;

// Рассылается при любом изменении положения окна AppBar.

ABN_POSCHANGED: begin

// Панель задач или какая-нибудь другая панель изменили

// размер или расположение.

SetAppBarPos(FABD.uEdge);

end;

end;          // case

end

else

inherited WndProc(M);

end;

Этот метод обрабатывает несколько уведомляющих сообщений, которые позволяют окну  AppBar  реагировать на  изменения, происходящие в оболочке во  время  работы приложения. Остальная часть кода компонента TAppBar приведена в листинге 16.3.

Листинг 16.3. AppBars.pas — модуль,  содержащий базовый класс для поддержки окна AppBar

unit AppBars;

interface

uses Windows, Messages, SysUtils, Forms, ShellAPI, Classes, Controls;

type

TAppBarEdge = (abeTop, abeBottom, abeLeft, abeRight);

EAppBarError = class(Exception);

TAppBar = class(TCustomForm)

private

FABD: TAppBarData;

FDockedHeight: Integer;

FDockedWidth: Integer;

FEdge: TAppBarEdge;

FOnEdgeChanged: TNotifyEvent;

FTopMost: Boolean;

procedure WMActivate(var M: TMessage); message WM_ACTIVATE;

procedure WMWindowPosChanged(var M: TMessage);

message WM_WINDOWPOSCHANGED;

function SendAppBarMsg(Msg: DWORD): UINT;

procedure SetAppBarEdge(Value: TAppBarEdge);

procedure SetAppBarPos(Edge: UINT);

procedure SetTopMost(Value: Boolean);

procedure SetDockedHeight(const Value: Integer);

procedure SetDockedWidth(const Value: Integer);

protected

procedure CreateParams(var Params: TCreateParams); override;

procedure CreateWnd; override;

procedure DestroyWnd; override;

procedure WndProc(var M: TMessage); override;

public

constructor CreateNew(AOwner: TComponent;

Dummy: Integer = 0); override;

property DockManager;

published

property Action;

property ActiveControl;

property AutoScroll;

property AutoSize;

property BiDiMode;

property BorderWidth;

property Color;

property Ctl3D;

property DockedHeight: Integer read FDockedHeight

write SetDockedHeight default 35;

property DockedWidth: Integer read FDockedWidth

write SetDockedWidth default 40;

property UseDockManager; property DockSite; property DragKind; property DragMode;

property Edge: TAppBarEdge read Fedge

write SetAppBarEdge default abeTop;

property Enabled;

property ParentFont default False;

property Font;

property HelpFile;

property HorzScrollBar;property Icon; property KeyPreview; property ObjectMenuItem; property ParentBiDiMode; property PixelsPerInch; property PopupMenu; property PrintScale; property Scaled;

property ShowHint;

property TopMost: Boolean read FTopMost

write SetTopMost default False;

property VertScrollBar; property Visible; property OnActivate; property OnCanResize; property OnClick; property OnClose; property OnCloseQuery;

property OnConstrainedResize;

property OnCreate;

property OnDblClick;

property OnDestroy;

property OnDeactivate;

property OnDockDrop;

property OnDockOver;

property OnDragDrop;

property OnDragOver;

property OnEdgeChanged: TNotifyEvent read FOnEdgeChanged

write FOnEdgeChanged;

property OnEndDock; property OnGetSiteInfo; property OnHide; property OnHelp; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnMouseWheel;

property OnMouseWheelDown; property OnMouseWheelUp; property OnPaint;

property OnResize; property OnShortCut; property OnShow; property OnStartDock; property OnUnDock;

end;

implementation varAppBarMsg: UINT;

constructor TAppBar.CreateNew(AOwner: TComponent; Dummy: Integer);

begin

FDockedHeight := 35;

FDockedWidth := 40;

inherited CreateNew(AOwner, Dummy);

ClientHeight := 35;

Width := 100;

BorderStyle := bsNone;

BorderIcons := [];

// Инициализация записи TAppBarData

FABD.cbSize := SizeOf(FABD);

FABD.uCallbackMessage := AppBarMsg;

end;

procedure TAppBar.WMWindowPosChanged(var M: TMessage);

begin

inherited;

// Проинформировать оболочку об изменении положения окна AppBar.

SendAppBarMsg(ABM_WINDOWPOSCHANGED);

end;

procedure TAppBar.WMActivate(var M: TMessage);

begin

inherited;

// Проинформировать оболочку об активизации окна AppBar

SendAppBarMsg(ABM_ACTIVATE);

end;

procedure TAppBar.WndProc(var M: TMessage);

var

State: UINT;

begin

if M.Msg = AppBarMsg then begin

case M.WParam of

// Рассылается при изменении свойств "всегда наверху" или

// "автосокрытие".

ABN_STATECHANGE: begin

// Проверка флага ABS_ALWAYSONTOP ("всегда наверху")

State := SendAppBarMsg(ABM_GETSTATE);

if ABS_ALWAYSONTOP and State = 0 then

SetTopMost(False)

else

SetTopMost(True);

end;

// Запущено (или закрыто последнее) полноэкранное

// приложение.

ABN_FULLSCREENAPP: begin

// Установить обратный порядок сортировки окон AppBar.

State := SendAppBarMsg(ABM_GETSTATE);

if M.lParam <> 0 then begin

if ABS_ALWAYSONTOP and State = 0 thenSetTopMost(False)

else

SetTopMost(True);

end else

if State and ABS_ALWAYSONTOP <> 0 then

SetTopMost(True);

end;

// Рассылается при любом изменении положения окна AppBar.

ABN_POSCHANGED:

// Панель задач или какая-нибудь другая панель изменили

// размер или расположение.

SetAppBarEdge(FEdge);

end; end else

inherited WndProc(M);

end;

function TAppBar.SendAppBarMsg(Msg: DWORD): UINT;

begin

// Не создавать AppBar во время разработки.

if csDesigning in ComponentState then Result := 0

else Result := SHAppBarMessage(Msg, FABD);

end;

procedure TAppBar.SetAppBarPos(Edge: UINT);

begin

if csDesigning in ComponentState then Exit;

FABD.uEdge := Edge;           // Установить границу экрана

with FABD.rc do begin

// Установить координаты в соответствии с размером

// полного экрана

Top := 0;

Left := 0;

Right := Screen.Width;

Bottom := Screen.Height;

// Послать сообщение ABM_QUERYPOS для получения прямоугольника

// соответствующих размеров у края экрана.

SendAppBarMsg(ABM_QUERYPOS);

// Перестроить прямоугольник в соответствии с информацией,

// полученной в ответ на сообщение ABM_QUERYPOS.

case Edge of

ABE_LEFT: Right := Left + FDockedWidth;

ABE_RIGHT: Left := Right – FDockedWidth;

ABE_TOP: Bottom := Top + FDockedHeight;

ABE_BOTTOM: Top := Bottom – FDockedHeight;

end;

// Установить позицию панели.

SendAppBarMsg(ABM_SETPOS);

end;

// Установить свойство BoundsRect согласно с ограничивающим

// прямоугольником, переданным системе.BoundsRect := FABD.rc;

end;

procedure TAppBar.SetTopMost(Value: Boolean);

const

WndPosArray: array[Boolean] of HWND = (HWND_BOTTOM,

HWND_TOPMOST);

begin

if FTopMost <> Value then begin

FTopMost := Value;

if not (csDesigning in ComponentState) then

SetWindowPos(Handle, WndPosArray[Value], 0, 0, 0, 0,

SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);

end;

end;

procedure TAppBar.CreateParams(var Params: TCreateParams);

begin

inherited CreateParams(Params);

if not (csDesigning in ComponentState) then begin

Params.ExStyle := Params.ExStyle or

WS_EX_TOPMOST or WS_EX_WINDOWEDGE;

Params.Style := Params.Style or WS_DLGFRAME;

end;

end;

procedure TAppBar.CreateWnd;

begin

inherited CreateWnd;

FABD.hWnd := Handle;

if not (csDesigning in ComponentState) then begin

if SendAppBarMsg(ABM_NEW) = 0 then

raise EAppBarError.Create(‘Failed to create AppBar’);

// Инициализировать позицию

SetAppBarEdge(FEdge);

end;

end;

procedure TAppBar.DestroyWnd;

begin

// Проинформировать оболочку об удалении панели AppBar

SendAppBarMsg(ABM_REMOVE);

inherited DestroyWnd;

end;

procedure TAppBar.SetAppBarEdge(Value: TAppBarEdge);

const

EdgeArray: array[TAppBarEdge] of UINT =

(ABE_TOP, ABE_BOTTOM, ABE_LEFT, ABE_RIGHT);

begin

SetAppBarPos(EdgeArray[Value]);

FEdge := Value;

if Assigned(FOnEdgeChanged) then FOnEdgeChanged(Self);end;

procedure TAppBar.SetDockedHeight(const Value: Integer);

begin

if FDockedHeight <> Value then begin

FDockedHeight := Value;

SetAppBarEdge(FEdge);

end;

end;

procedure TAppBar.SetDockedWidth(const Value: Integer);

begin

if FDockedWidth <> Value then begin

FDockedWidth := Value;

SetAppBarEdge(FEdge);

end;

end;

initialization

AppBarMsg := RegisterWindowMessage(‘DDG AppBar Message’);

end.

Использование компонента TAppBar

Если установить программный продукт  с компакт  диска, прилагаемого к этой  кни ге, то использование компонента TAppBar не вызовет никаких трудностей: достаточ но выбрать в меню  File пункт  New dialog, а затем  во вкладке  DDG диалогового окна параметр AppBar —   и  вызванный мастер   немедленно  создаст   модуль,  содержащий компонент TAppBar.

НА ЗАМЕТКУ

В главе 17, “Применение интерфейса API Open Tools”, будет показано, как создать мастер, который автоматически генерирует компонент TAppBar. Для задач, решаемых в настоящей главе, можно вполне обойтись и без рассмотрения реализации мастера. Просто примите сейчас к сведению то, что часть работы по созданию формы и соот- ветствующего модуля выполняется “за кулисами”.

Ниже  приведен код небольшого приложения, использующего компонент TAppBar для создания панели инструментов на рабочем столе  приложения с кнопками для вы полнения различных команд  редактирования и  работы с файлами: Open, Save, Cut, Copy и Paste. С помощью этих кнопок можно  управлять компонентом TMemo, располо женным в главной форме. Код главного модуля приложения приведен в листинге 16.4, а на рис. 16.5 данное  приложение показано в действии — создана  панель  AppBar,  которая закреплена на верхней границе экрана.

Листинг 16.4. ApBarFrm.pas — главный  модуль  приложения, демонстрирующего использование окна AppBarunit ApBarFrm;

interface uses

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

Dialogs, AppBars, Menus, Buttons;

type

TAppBarForm = class(TAppBar)

sbOpen: TSpeedButton;

sbSave: TSpeedButton;

sbCut: TSpeedButton;

sbCopy: TSpeedButton;

sbPaste: TSpeedButton;

OpenDialog: TOpenDialog;

pmPopup: TPopupMenu;

Top1: TMenuItem;

Bottom1: TMenuItem;

Left1: TMenuItem;

Right1: TMenuItem;

N1: TMenuItem;

Exit1: TMenuItem;

procedure Right1Click(Sender: TObject);

procedure sbOpenClick(Sender: TObject);

procedure sbSaveClick(Sender: TObject);

procedure sbCutClick(Sender: TObject);

procedure sbCopyClick(Sender: TObject);

procedure sbPasteClick(Sender: TObject);

procedure Exit1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure FormEdgeChanged(Sender: TObject);

private

FLastChecked: TMenuItem;

procedure MoveButtons;

end;

var

AppBarForm: TAppBarForm;

implementation uses Main;

{$R *.DFM}

{ TAppBarForm }

procedure TAppBarForm.MoveButtons;

{ Этот метод выглядит сложным, но на самом деле он просто размещает

кнопки в зависимости от того, к какой стороне экрана прикреплена

панель AppBar. }

varDeltaCenter, NewPos: Integer;

begin

if Edge in [abeTop, abeBottom] then begin

DeltaCenter := (ClientHeight – sbOpen.Height) div 2;

sbOpen.SetBounds(10, DeltaCenter, sbOpen.Width,

sbOpen.Height);

NewPos := sbOpen.Width + 20;

sbSave.SetBounds(NewPos, DeltaCenter, sbOpen.Width,

sbOpen.Height);

NewPos := NewPos + sbOpen.Width + 10;

sbCut.SetBounds(NewPos, DeltaCenter, sbOpen.Width,

sbOpen.Height);

NewPos := NewPos + sbOpen.Width + 10;

sbCopy.SetBounds(NewPos, DeltaCenter, sbOpen.Width,

sbOpen.Height);

NewPos := NewPos + sbOpen.Width + 10;

sbPaste.SetBounds(NewPos, DeltaCenter, sbOpen.Width,

sbOpen.Height);

end else begin

DeltaCenter := (ClientWidth – sbOpen.Width) div 2;

sbOpen.SetBounds(DeltaCenter, 10, sbOpen.Width,

sbOpen.Height);

NewPos := sbOpen.Height + 20;

sbSave.SetBounds(DeltaCenter, NewPos, sbOpen.Width,

sbOpen.Height);

NewPos := NewPos + sbOpen.Height + 10;

sbCut.SetBounds(DeltaCenter, NewPos, sbOpen.Width,

sbOpen.Height);

NewPos := NewPos + sbOpen.Height + 10;

sbCopy.SetBounds(DeltaCenter, NewPos, sbOpen.Width,

sbOpen.Height);

NewPos := NewPos + sbOpen.Height + 10;

sbPaste.SetBounds(DeltaCenter, NewPos, sbOpen.Width,

sbOpen.Height);

end;

end;

procedure TAppBarForm.Right1Click(Sender: TObject);

begin

FLastChecked.Checked := False;

(Sender as TMenuItem).Checked := True;

case TMenuItem(Sender).Caption[2] of

‘T': Edge := abeTop;

‘B': Edge := abeBottom;

‘L': Edge := abeLeft;

‘R': Edge := abeRight;

end;

FLastChecked := TMenuItem(Sender);

end;

procedure TAppBarForm.sbOpenClick(Sender: TObject);

begin

if OpenDialog.Execute then

end;

MainForm.FileName := OpenDialog.FileName;procedure TAppBarForm.sbSaveClick(Sender: TObject);

begin

MainForm.memEditor.Lines.SaveToFile(MainForm.FileName);

end;

procedure TAppBarForm.sbCutClick(Sender: TObject);

begin

MainForm.memEditor.CutToClipboard;

end;

procedure TAppBarForm.sbCopyClick(Sender: TObject);

begin

MainForm.memEditor.CopyToClipboard;

end;

procedure TAppBarForm.sbPasteClick(Sender: TObject);

begin

MainForm.memEditor.PasteFromClipboard;

end;

procedure TAppBarForm.Exit1Click(Sender: TObject);

begin

Application.Terminate;

end;

procedure TAppBarForm.FormCreate(Sender: TObject);

begin

FLastChecked := Top1;

end;

procedure TAppBarForm.FormEdgeChanged(Sender: TObject);

begin

MoveButtons;

end;

end.

Рис. 16.5. Компонент TAppBar в действии

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

По теме:

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