Глава 17

ОБЩИЕ СВОЙСТВА КОМПОНЕНТОВ

Компонентами в Delphi называются потомки класса TComponent. В этой главе описываются общие свойства, методы и события компонентов. В остальных разделах книги при описании конкретного компонента эти свойства уже не упоминаются. Следует учесть, что все они относятся в основном к классам-родоначальникам TObject, TPersistent, TComponent и TControl.

Некоторые из них описаны в секциях protected этих классов и могут быть недоступны своим потомкам. Поэтому для получения полного набора методов, свойств и событий конкретного компонента необходимо обращаться к встроенной справочной службе Delphi.

17.1. ИЕРАРХИЯ КОМПОНЕНТОВ

Все компоненты Delphi порождены от класса TComponent, в котором инкапсулированы самые общие свойства и методы компонентов. Предком TComponent является класс TPersistent, который произошел непосредственно от базового класса TObject.

Класс TPersistent передает своим потомкам важный виртуальный метод

procedure Assign(Source: TPersistent);

с помощью которого поля и свойства объекта source копируются в объект, вызвавший метод Assign.

Замечу, что обмениваться данными могут все наследники TPersistent независимо от того, находятся ли они в непосредственном родстве по отношению друг к другу или имеют единственного общего Предка - TPersistent.

Класс TComponent служит базой для создания как видимых, так и невидимых компонентов.

Большинство видимых компонентов происходит от класса ТСоntrol. Два наследника этого класса - TWinControl И TGraphicControопределяют две группы компонентов: имеющие оконный ресурс

rwincontroi и его потомки) и не имеющие этого ресурса

TGraphicControl и его потомками).

Оконный ресурс - это специальный ресурс Windows, предназначенный для создания и обслуживания окон. Только оконные компоненты способны получать и обрабатывать сообщения Windows. 

Оконный компонент в момент своего создания обращается к Windows с требованием выделения оконного ресурса и, если требование удовлетворено, получает так называемый дескриптор окна. TWinControl и его потомки хранят дескриптор окна в свойстве Handle.

Программист может использовать этот дескриптор для непосредственного обращения к API-функциям Windows. 1 Потомки TGraphicControl не требуют от Windows дефицитного оконного ресурса, но они и не могут получать и обрабатывать Win-jows-сообщения - управляет такими элементами оконный компонент-владелец (например, форма), который является посредником между Windows и не оконными компонентами.

17.2. ИМЕНА И СОБСТВЕННИКИ КОМПОНЕНТОВ

Класс TComponent включает в себя свойства и методы, общие для всех компонентов.

Свойство

property Name: TComponentName;

type TComponentName = String; // Delphi 32

type TComponentName = String[63]; // Delphi 1

определяет имя компонента. Имя компонента строится по тем же правилам, что и имена любых других объектов программирования - констант, переменных, подпрограмм и т. д.: оно представляет собой правильный идентификатор и должно быть уникальным в области своей видимости в программе. Так как компоненты помещаются на форму средой Delphi, каждый компонент автоматически получает создаваемое средой имя, совпадающее с именем своего класса (без начальной буквы Т) и дополненное числовым суффиксом: Form1, Labell2, RichEdit2 И Т. Д.

Впоследствии программист может переименовать компонент, чтобы сделать текст программы более “читабельным”. При разработке собственных имен полезно выработать свою систему двух- или трехбуквенных префиксов, кодирующих тип компонента.

Например fm - для формы TForm, ib - для метки TLabel, ed - для редактора TEdit и т. п. Комбинируя префикс с мнемоническим именем, можно существенно улучшить читаемость программы и усилить контроль за правильным использованием свойств и методов компонента.

Например, оператор

IbOutput.Text := 'Текст';

сразу вызовет подозрение, т. к. префикс ib определяет компонент TLabel, который не имеет свойства или поля с именем Text. Свойство

property Tag: Integer;

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

Любой компонент Delphi является собственностью другого компонента и, в свою очередь, может быть владельцем одного или нескольких компонентов. Такая зависимость компонентов друг от

друга позволяет существенно упростить процесс управления ими. Например, чтобы уничтожить окно с включенными в него компонентами, достаточно вызвать деструктор окна: он поочередно вызовет деструкторы всех других компонентов, владельцем которого является компонент-окно, и таким образом полностью освободит выделенные окну ресурсы. Свойство

property Owner: TComponent;

указывает на владельца компонента (это свойство доступно только для чтения), а свойство

property Componentlndex: Integer;

на положение компонента в массиве components своего владельца. Этот массив определяется свойством

property Components[Index: Integer]: TComponent;

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

property ComponentCount: Integer;

Конструктор TComponet. Create имеет единственный параметр обращения:

constructor Create(AOwner: TComponent);

в котором компоненту передается ссылка на его владельца. В ходе выполнения конструктора компонент вставляет ссылку на себя в список Components своего владельца и изменяет содержимое собственного свойства Owner.

Для управления списком components предназначены следующие методы:

procedure DestroyComponents;

Вызывает поочередно деструкторы всех компонентов из списка Components и удаляет все компоненты из списка

function FindComponent(constName: String): TComponent;

Отыскивает в списке компонент с именем AName и возвращает ссылку на него

procedure insertComponent AComponent: TComponent);

Вставляет компонент AComponent в конец списка Components

procedure RemoveComponent AComponent: TComponent);

Удаляет компонент AComponent из списка

17.3. РОДИТЕЛЬСКИЕ И ДОЧЕРНИЕ КОМПОНЕНТЫ

Класс TControl со своими наследниками образуют всю палитру видимых компонентов Delphi. Терминологически они называются элементами управления, так как на их основе прежде всего реализуются управляющие элементы Windows - кнопки, переключатели, списки и т. п. В тексте книги я часто буду употреблять слова компонент и элемент как синонимы.

Как уже отмечалось, некоторые из наследников TControl обладают дескрипторами окон и способны получать и обрабатывать Wwdows-сообщения, другие окон не имеют, но обязательно включаются в состав оконных компонентов, которые управляют ими, согласуясь с требованиями (сообщениями) Windows. Оконные элементы управления обладают специальной оконной функцией, в которую Windows посылает управляющие сообщения (например, извещения о манипуляции пользователя с мышью или о нажатии клавиш клавиатуры). В терминологии Windows такие элементы называются родительскими, а связанные с ними неоконные элементы - дочерними. Замечу, что оконный компонент может выступать как родительский не только по отношению к неоконным компонентам, но и к оконным. В этом случае он просто транслирует управляющие сообщения Windows в оконные функции дочерних компонентов. Обязательным требованием Windows является визуальная синхронизация дочерних элементов: они не могут выходить из границ своего родителя и появляются и исчезают вместе с ним. Иными словами, родитель с дочерними элементами рассматривается Windows как единое целое.

Класс TControl определяет свойство parent, которое содержит ссылку на родительский компонент:

property Parent: TWinControl;

Это свойство не следует путать с собственником owner: owner создал компонент (не обязательно - видимый), a parent управляет видимым компонентом. поскольку конструктор TComponent. Create не

изменяет свойства parent (в родительском классе TComponent такого свойства нет), при создании видимых компонентов на этапе прогона программы это свойство необходимо изменять программно. Например, Следующий обработчик События OnCreate формы Form1

вставит надпись дочерний элемент в левый верхний угол формы:

procedure TFormI.FormCreate(Sender: TObject);

var

IbLabel: TLabel;

begin

IbLabel := TLabel.Create(Self);

IbLabel.Parent := Self;

IbLabel.Caption := 'Дочерний элемент';

end;

Если убрать оператор

IbLabel.Parent := Self;

метка никогда не узнает о том, что пришла пора прорисовать себя на экране, и ее текст не будет виден. Наоборот, изменение свойства parent подключает метку к списку дочерних элементов формы, и оконная функция формы обратится к нужному методу метки, чтобы заставить ее появиться на экране в момент появления самой формы. (Замечу, что приведенный выше пример является образчиком того, как не надо программировать: локальная переменная IbLabel будет уничтожена после выхода из процедуры FormCreate, содержащийся в ней указатель будет безвозвратно потерян для программы, и она никогда не сможет освободить связанные с меткой ресурсы памяти[ На самом деле ресурсы будут автоматически освобождены при завершении работы программы.]. Правильнее было бы расположить переменную IbLabel вне процедуры, например, в секции public класса TForm1, чтобы в обработчике события OnDestroy формы выполнить вызов деструктора метки.)

Помимо свойства components каждый оконный компонент получает от своего родителя TWinControl свойство property Controls[Index: Integer]: TControl;

содержащее список дочерних элементов. Свойство

property ControlCount: Integer;

возвращает количество дочерних элементов (длину массива controls). Работать со списком controls можно с помощью следующих методов:

function ContainsControl( Control: TControl): Boolean;

Возвращает True, если компонент Control является дочерним элементом

function ControlAtPos(constPos: TPoint; AllowDisabled: Boolean): TControl;

Возвращает ссылку на компонент, которому

принадлежит точка с координатами Роз. Если AllowDisabied=True, поиск ведется также среди запрещенных для выбора компонентов

function FindNextControl ( Curcontrol: TWinControl; GoForward, CheckTabStop, CheckParent: Boolean): TWinControl;

Ищет новый элемент в списке Controls. Cur-control определяет начальную позицию поиска; GoForward=True, если поиск идет от начальной позиции к концу списка; CheckTab Stop=True, если поиск идет только среди

компонентов со свойством TabStop=True;

если checkParent=True, поиск идет только

среди оконных элементов

procedure GetTabOrderListfList: TList) ;

Создает список List всех дочерних компонентов в порядке их выбора клавишей Tab

procedure InsertCon-

trol(AControl: TControl);

Вставляет новый дочерний элемент в список Controls. Программа не должна обращаться непосредственно к этому методу: для вставки дочернего элемента следует установить нужное значение свойства Parent во вставляемом компоненте

procedure NotifyControls(Msg:

Word) ;

Посылает сообщение Msg во все дочерние оконные компоненты

procedure PaintControls(DC:

HDC; First: TControl);

Перерисовывает все дочерние компоненты начиная с компонента First. Каждый дочерний компонент получает дескриптор графического устройства DC, с помощью которого он сможет прорисовать себя

procedure Realign;

Перерисовывает все компоненты со свойством Align не равным noAlign. Вызывается после изменения размеров родительского компонента.

procedure Repaint;

Перерисовывает родительский компонент и

все его дочерние компоненты

procedure ScaleControls(M, D:Integer) ;

Перерисовывает все дочерние элементы с раз мерами, измененными в M./D раз по сравнению с предыдущими размерами

procedure SelectFirst;

Выбирает первый в порядке обхода клавишей Tab дочерний компонент

procedure SelectNext(CurControl: TWinControl; GoForward, CheckTabStop:

Boolean) ;

Выбирает очередной в порядке обхода клавишей Tab дочерний компонент. CurControl определяет начальную точку поиска; GoForward= True, если поиск идет к концу списка; CheckTabStop=True, если выбираются только компоненты со свойством TabStop=True

procedure SetChildOrder(Child:TComponent; Order: Integers-

Устанавливает новый порядок выбора клавишей Tab компонента Child

procedure ShowControl(AControl:TControl);

Показывает дочерний компонент Acontrol

В некоторых случаях бывает необходимо послать сообщение в собственную оконную функцию, чтобы заставить компонент выполнить действия, не предусмотренные набором его свойств и методов. Для посылки сообщения служит метод

function Perform(Msg, WParam: Word; LParam: Longint): Longint;

Параметры обращения к методу соответствуют параметрам вызова

оконной функции: Msg - код сообщения; WParam, LParam - уточняющие параметры.

17.4. ПОЛОЖЕНИЕ, РАЗМЕРЫ И ОФОРМЛЕНИЕ КОМПОНЕНТОВ

Положение и размеры компонента определяются четырьмя его свойствами (в пикселях):

property Height: Integer; // Высота

property Left: Integer;// Положение левой кромки

property Top: Integer;// Положение верхней кромки

property Width: Integer;// Ширина

Для всех компонентов, кроме форм, эти свойства задаются в координатах клиентской части родительского компонента. Для формы - в координатах экрана. Клиентская часть компонента - это внутренняя его область за исключением заголовка, рамки и меню. Свойства обычно определяются на стадии конструирования формы, но они доступны также и на этапе прогона программы. Изменение любого из них приводит к немедленному изменению положения или размера компонента как на этапе конструирования, так и при прогоне программы. Все четыре числовые величины содержатся также в единственном свойстве

property BoundsRect: TRect;

type

TPoint = record X: Longint;

Y: Longint;

end;

TRect = record case Integer of

0: (Left, Top, Right, Bottom: Integer);

1: (TopLeft, BottomRight: TPoint);

end;

Это свойство удобно использовать при прорисовке компонента методом TCanvas . FrameRect.

В некоторых случаях бывает необходимо пересчитать относительные координаты точки внутри клиентской части в абсолютные координаты экрана и наоборот. Эта задача решается двумя методами Control:

function ClientToScreen(const Point: TPoint): TPoint;

function ScreenToClient(const Point: TPoint): TPoint;

Важную роль играет свойство Align, определяющее выравнивание положения компонента относительно границ своего родителя:

type TAlign = (aINone, alTop, alBottom, alLeft, alRight, alClient) ;

property Align: TAlign;

Если это свойство не равно aiNone, компонент прижимается к верхней (alTop), нижней (alBottom), левой (alLeft) или правой (alRight) границе своего родителя. При этом размеры компонента по соседним с границей измерениям игнорируются, и компонент “растекается” по границе. Например, если Align=alTop, значения свойств компонента Left и width игнорируются и его прямоугольник будет занимать всю верхнюю часть клиентской области родителя высотой Height пикселей; если Align=alLeft, свойства тор и Height игнорируются и прямоугольник занимает левую часть родителя шириной width пикселей и т. д. Если несколько компонентов имеют одинаковое выравнивание, они последовательно прижимаются друг к другу в порядке их перечисления в свойстве controls: первый прижимается к границе родителя, второй - к границе первого и т. д. Вся не заполненная другими компонентами клиентская область родителя заполняется компонентами со свойствами Align=alClient, которые в этом случае накладываются друг на друга. Замечательной особенностью свойства является его постоянство при изменении размеров клиентской части родителя. Если, например, компонент прижат к верхней границе формы, он будет неизменно занимать верхнюю часть клиентской области при любых изменениях размеров окна. Таким способом можно легко реализовать панели с инструментальными кнопками, панели статуса и т. п. Временное отключение и затем включение эффекта от свойства Align обеспечивается методами

procedure DisableAlign;

procedure EnableAlign;

Любой видимый компонент можно спрятать или показать с помощью свойства visible или методами Hide и show:

property Visible: Boolean; // True - показывает

procedure Hide; // Прячет компонент

procedure Show; // Показывает компонент

Спрятанный компонент не реагирует на события от мыши или клавиатуры, он не участвует в дележе клиентской области родителя, ему нельзя передать фокус ввода клавишей Tab.

Если компонент частично или полностью перекрывается другими компонентами, его можно расположить над всеми компонентами и убрать обратно с помощью методов

procedure BringToFront; // Сделать верхним

procedure SendToBack; // Сделать нижним

Свойство

property Enabled: Boolean;

определяет возможность активизации компонента. Если оно имеет значение False, компонент запрещен для выбора. Такие компоненты (точнее, надписи на них) обычно отображаются серым цветом.

Некоторые компоненты имеют плоское изображение (например, метка TLabel), другие - всегда объемное (например, кнопка TButton).

Для остальных элементов объемность изображения регулируется свойством

property Ctl3D: Boolean;

С каждым управляющим компонентом связывается текстовая строка, которая становится доступна либо через свойство Caption, либо через свойство Text (альтернативой свойству Text, которое имеет тип string, является свойство TControi.windowsText типа pchar). Независимо от того, какое свойство хранит эту строку, ее можно установить и получить соответственно методами setTextBuf и GetTextBuf, при этом метод GetTextLen возвращает длину строки:

procedure SetTextBuf(Buffer: PChar);

function GetTextBuf(Buffer: PChar; BufSize: Integer): Integers;

function GetTextLen: Integer;

Если эта строка выводится в компоненте, используется шрифт, задаваемый свойством Font:

property Font: TFont;

В этом случае свойство

type TAlignment = (taLeftJustify, taRightJustify, taCenter);

property Alignment: TAlignment;

регулирует расположение текста относительно границ компонента:

taLeftJustify - прижать к левой границе; taRightJustify - прижать к правой границе; taCenter - расположить по центру.

С помощью придания свойству

property DesktopFont: Boolean;

значения True можно потребовать от компонента, чтобы он выводил текст системным шрифтом Windows.

Видимая часть элемента заливается цветом Color:

property Color: TColor;

Обычно значение этого свойства выбирается из таблицы стандартных цветов Windows в виде константы clxxxx (перечень этих констант содержит раскрывающийся список свойства). В некоторых случаях может потребоваться залить компонент нестандартным цветом. В этом случае учтите, что свойство Color хранит четырехбайтное значение, каждый байт которого (слева направо, т. е. от старшего к младшему) имеет следующее назначение:

составляющих.

Например, значение $00000000 определяет черный цвет, $00ff0000 -чистый синий цвет, $00ffffff - белый цвет и т. д.

Старший байт указывает, как используются остальные байты значения. Если он равен нулю, они определяют RGB-цвет так, как это описано выше. Если старший байт равен 1, три оставшихся байта определяют номер одной из 65536 возможных логических палитр (второй байт в этом случае игнорируется). Наконец, если старший байт равен 2, младшие определяют относительный цвет: в этом случае Windows отыскивает в текущей логической палитре ближайший к указанному цвет и использует его для заливки компонента. Другие значения старшего байта игнорируются (точнее, игнорируются старшие 5 разрядов этого байта; самый старший бит, если он равен 1, определяет черный цвет независимо от значений остальных 31 разрядов).

Чтобы разнообразить унылые серые окна программы, соответствующие стандартным формам Delphi, я иногда использую значение $00AAffff, определяющее бледно-желтый цвет (в свойство color можно вводить значения в виде десятичных или шестнадцатеричных чисел). Получить шестнадцатеричное значение того или иного цвета вам поможет несложная программа, окно которой показано на рис. 17.1. С ее помощью можно выбрать цвет в окне компонента TColor-Dialog (см. дальше п. 17.5.4) и получить его шестнадцатеричное представление или ввести шестнадцатеричное число и увидеть соответствующий ему цвет.

Рис. 17.1. Окно програлшы для определения цветовых констант

  1. Положите на пустую форму две панели - они будут наглядно демонстрировать цвет, выбранный с помощью TCoiorDialog (левая панель), и цвет, заданный с помощью 16-ричной константы (правая панель). Установите в свойство Align панели Panel1. Значение alRight, а в такое же свойство Рапе12 - alClient.
  2. На левую панель положите кнопку TButtcni и диалог TCoiorDialog (этот компонент находится на странице Dialogs палитры компонентов). В значение caption кнопки поместите строку. Выбор цвета.
  3. На правую панель положите редактор TEdit и кнопку TButton. В свойство charCase редактора поместите значение ecupper-case - это заставит компонент преобразовывать вводимые в нем буквы к заглавным и упростит дальнейший их анализ. В Caption кнопки поместите Ввод константы.
  4. Напишите такой обработчик события OnClick кнопки Button1 (в нем открывается диалоговое окно компонента ColorDialog1, закрашивается выбранным цветом левая панель panel 1, в заголовок окна помещается десятичное представление цветовой константы, а в редактор Editi - ее 16-ричное представление:

procedure TFormI.ButtonlClick(Sender: TObject) ;

begin

{Вызываем диалог CoiorDiaiogi и контролируем его результат:

если его метод Execute возвращает True, пользователь выбрал нужный цвет:}

if CoiorDiaiogi.Execute then begin

//В заголовок окна помещаем iu-чное представление цвета:

Caption := IntToStr(CoiorDiaiogi.Color);

//Закрашиваем левую панель выбранным цветом:

Рапе12.Color := CoiorDiaiogi.Color;

//Помещаем в Edit1 и в заголовок левой панели 16-ричное

// представление цвета:

Editl.Text := IntToHex(ColorDialogl.Color,8);

Panel2.Caption := Editl.Text

end

end;

5. В обработчике события нажатия правой кнопки нужно преобразовать введенное в редакторе 16-ричное представление цветовой константы в целое число и поместить его в свойство caption правой панели. Поскольку нет стандартной функции преобразования символьного представления 16-ричной константы в число, обработчик использует вспомогательную функцию HexStrToInt:

function HexStrToint(S: String): Integer;

(Функция преобразует 16-ричное представление S целого числа в тип Integer} function HDigitaKC: Char): Byte;

//Преобразует 16-ричную цифру С в число

begin

case С of 'О'..'9': Result := ord(C)-ord('0');

'A'..'F': Result := ord(C)-ord('A')+10;

else

{Если очередной символ не относится к допустимым для представления 16-ричной цифры, возбуждаем исключительную ситуацию, которая блокирует преобразование и сообщает пользователю об ошибке:}

raise EConvertError.Create

('Недопустимое представление 16-ричного числа');

end;

end; //HDigital

var

k: Integer;

begin //HexStrToInt

Result := 0;

//Удаляем возможный символ-указатель 16-ричного числа:

if S[1]='$' then delete(S,1,1) ;

//Цикл преобразования строки:

for k := 1 to Length (S) do

Result := Result*16+HDigital(S[k]);

end; //HexStrToInt

procedure TForml.Button2Click(Sender: TObject);

begin

Panell.Color := StrToHex(Editl.Text);

Panell.Caption := Edit1.Text

end;

Для упрощения разработки интерфейсных элементов, выдержанных в едином стиле, в состав видимых компонентов включены свойства, связывающие ту или иную особенность оформления или поведения компонента с соответствующей особенностью родителя. Таких свойств четыре:

property ParentColor: Boolean;

property ParentCtl3d: Boolean;

property ParentFont: Boolean;

property ParentHint: Boolean;

Если, например, цвет компонента не задан явно свойством color и его свойство ParentColor имеет значение True, компонент будет использовать при прорисовке цвет своего родителя, а изменение цвета родителя приведет к немедленному изменению цвета дочернего компонента. Явная установка значений свойств color, Cti3D, Font или Hint приводит к автоматической установке значений False в соответствующие свойства ParentXXX.

Некоторые компоненты очерчиваются двойной кромкой - внешней и внутренней. В класс TWinControl Delphi 4 введены специальные свойства, управляющие трехмерным эффектом, создаваемым такими кромками:

type

TBevelEdge = (beLeft, beTop,

oeRight, beBottom) ; TBevelEdges = set of TBevelEdge; property BevelEdges: TBevelEdges;

Определяет стороны компонента, которые будут содержать кромки: beLeft -левая; bеТор - верхняя; beRight - правая; beBot tom - нижняя

type TBevelCut = (bvNone, bvLow-

ered, bvRaised, bvSpace) ;

property Bevellnner: TBevelCut;

Определяет тип внутренней кромки: bvNone- нет рамки; bvLowered. - вдавленная кром ка; bvRaised - выпуклая кромка; bvSpace -кромки нет, но для нее отводится место толщиной 1 пиксель

type TBevelKind = (bkNone,

okTile, bkSoft, bkFlat) ;

property BevelStyle: TBevelKind;

Указывает тип кромок: bkNone - нет кромок; bkTile - есть внутренняя и внешняя кромка; bksoft - то же, что и bkTile, но менее контрастная внешняя кромка; bkFlat - есть только внешняя кромка толщиной 1пиксель

property BevelOuter: TBevelCut;

Определяет тип внешней кромки

type TBevelWidth = l..Max!nt;

property BevelWidth: TBevelWidth;

Задает толщину линий кромки

type TBorderWidth = O..MaxInt;

property BorderWidth: TBorder Width;

Определяет расстояние в пикселях от внешней кромки до внутренней

В версиях Delphi 4 ... 6 в класс TControl введено свойство

property Anchors: TAnchors;

type TAnchors = set of TAnchorKind;

type TAnchorKind = (akTop, akLeft, akRight, akBottom);

определяющее способ фиксирования дочернего компонента относительно границ контейнера, в котором он размещен. По умолчанию это свойство имеет значение [akTop, akLeft], что означает фиксацию компонента относительно левого верхнего угла контейнера. В результате возможные изменения размеров контейнера никак не скажутся на изменении положения и/или размеров компонента. Если установить значение [akRight, akBottom], правая и нижняя кромки компонента всегда будут располагаться на одном и том же расстоянии от соответствующих кромок контейнера. Так как положение левого верхнего угла компонента при этом не фиксируется, он будет “плавать” внутри контейнера, всегда располагаясь на одном и том же расстоянии от его правой и нижней кромки. Однако, если установлено значение [akTop, akLeft, akRight, akBottom], левый верхний угол будет зафиксирован, и компонент будет пытаться отслеживать расстояние до правого нижнего угла контейнера с помощью изменения своих размеров. Поместите на пустую форму редактор TEdit и поэксперименти-руйте с его свойством Anchors, каждый раз изменяя мышью размеры формы (не обязательно запускать программу - свойство Anchors работает и на этапе конструирования). В Delphi 4... 6 введено свойство

property Constraints: TSizeConstraints;

Оно используется для ограничения максимальных и минимальных размеров управляющих элементов по высоте и ширине. Объект класса TSizeConstraint имеет четыре следующих свойства: Max-Height, MaxWidth, MinHeight, MinWidth типа O..MaxInt, которые и определяют предельные значения указанных параметров. По умолчанию эти свойства имеют нулевые значения, что эквивалентно снятию каких бы то ни было ограничений.

Свойство

property AutoSize: Boolean;

также впервые введено в Delphi 4. Оно связано, в основном, с интерфейсом Drag&Dock (см.п. 17.8) и разрешает (True) или запрещает (False) оконному компоненту автоматически изменять свои размеры в зависимости от количества и размеров содержащихся в нем неоконных компонентов.

17.5. УКАЗАТЕЛИ МЫШИ

При перемещении указателя мыши по экрану он может менять свою форму в зависимости от свойства Cursor компонента, над которым он расположен в данный момент:

property Cursor: TCursor;

type TCursor = -32768..+32767;

В Delphi предопределены стандартные указатели, показанные на рисунке 17.2.

Рис. 17.2. Стандартные курсоры Delphi

В практике программирования часто возникает необходимость изменения формы указателя для всех окон программы. Например, при выполнении достаточно длительного по времени процесса указатель мыши часто принимает вид crHourGlass, а после завершения процесса - восстанавливает свой первоначальный вид. Чтобы изменить форму указателя для всех окон программы одновременно, используется свойство cursor у глобального объекта screen, который автоматически создается для каждой программы:

Screen.Cursor := crHourGiass;

..... //Делаем длительную работу

Screen.Cursor := crDefault; // Восстанавливаем начальную

// форму указателя

Программист может создать и использовать нестандартный указатель. При этом он должен:

Рассмотрим процесс создания и использования нестандартного указателя на следующем примере, в котором создается и используется указатель в виде окружности.

Рис. 17.3. Окно редактора изображений с заготовкой для указателя мыши

{$R *.DFM} ($R Cursor.res}

procedure TForm1.FormCreate(Sender: TObject);

begin

// Регистрируем указатель:

Screen.Cursors[1] := LoadCursor(HInstance,'MYCURSOR');

// Используем его для клиентской части формы:

Cursor := 1

end;

Не забудьте указать комментарий {$r cursor, res}, чтобы компоновщик пристыковал ресурсный файл cursor, res к ресурсному файлу программы. После запуска программы вы увидите в клиентской части пустой формы нестандартный указатель. Замечу, что при регистрации указателя в screen, cursors индекс может быть любым числом в диапазоне от -32768 до +32767. Однако следует учитывать,

что индексы в диапазоне от -22 до -1 включительно заняты стандартными указателями, показанными на рис. 17.3 (индексы -5 и -1 соответствуют указателю crNone), а индекс 0 всегда связан со стандартным указателем Windows ^ и не может переопределяться.

Рис. 17.4. Окно редактора с готовым изображением указателя

17.6. РЕАКЦИЯ НА СОБЫТИЯ ОТ МЫШИ И КЛАВИАТУРЫ

17.6.1. События от мыши

Для большинства видимых компонентов определен набор обработчиков событий, связанных с мышью:

type

TMouseButton = (mbLeft, mbRight, mbMiddle) ;

TShiftState = set of (ssShift, ssAlt, ssCtrl, ssLeft,

ssRight, ssMiddle, ssDouble);

TMouseEvent = procedure (Sender: TObject;

Button: TMouseButton;

Shift: TShiftState; X, Y: Integer) of object;

TMouseMoveEvent = procedure(Sender: TObject;

Shift: TShiftState; X, Y: Integer) of object;

TNotifyEvent = procedure (Sender: TObject) of object-property OnMouseDown: TMouseEvent;

property OnMouseUp: TMouseEvent;

property OnMouseMove: TMouseMoveEvent;

property OnClick: TNotifyEvent;

property OnDblClick: TNotifyEvent;

Тип TMouseButton определяет одну из трех кнопок мыши: левую

(mbLeft), правую (mbRigth) и среднюю (mbMiddle).

Тип TShiftState содержит признаки, уточняющие обстоятельства возникновения события: ssShift - нажата клавиша Shift; ssAit -нажата клавиша Alt; ssctri - нажата клавиша Ctrl; ssLeft - нажата левая кнопка мыши; ssRight - нажата правая кнопка; ssMiddie -нажата средняя кнопка; ssDoubie - нажаты одновременно левая и правая кнопки.

Обработчики OnMouseDown и OnMouseUp определяют реакцию программы на соответственно нажатие и отпускание кнопки мыши, оп-MouseMove - на перемещение указателя мыши над компонентом, оп-click и OnDblClick - соответственно на щелчок и двойной щелчок левой кнопки. Во всех обработчиках параметр sender содержит ссылку на компонент, над которым произошло событие, а х и y определяют координаты точки чувствительности указателя мыши в момент возникновения события в системе координат клиентской области родительского компонента. Замечу, что событие OnClick возникает после OnMouseDown, но перед OnMouseUp, а событие

OnDblClick Возникает после OnMouseUp.

17.6.2. События от клавиатуры

События от мыши получают любые потомки TControl. В отличие от этого события от клавиатуры получают только некоторые оконные компоненты (потомки TWinControi). Обработка событий связана со следующими свойствами этих компонентов:

type

TShiftState = set of (ssShift, ssAlt, ssCtrl, ssLeft,

ssRight, ssMiddie, ssDoubie) ;

TKeyEvent = procedure (Sender: TObject; var Key: Word;

Shift: TShiftState) of object;

TKeyPressEvent = procedure (Sender: TObject;

var Key: Char) of object-property OnKeyDown: TKeyEvent;

property OnKeyUp: TKeyEvent;

property OnKeyPress: TKeyPressEvent;

Параметр Shift, как и в обработчиках событий от мыши, содержит уточняющие признаки. Параметр Key в обработчиках TKeyEvent содержит виртуальный код клавиши, а в обработчике TKeypressEv-ent - ASCII-символ. Обработчики OnKeyDown и опкеуор перехваты-вают нажатие большинства клавиш клавиатуры, в то время как обработчик QnKeypress - только нажатие алфавитно-цифровых клавиш. Получаемый им символ Key учитывает выбранный язык и нажатую клавишу Shift.

Виртуальные коды клавиш определены константами vk_xxx в файле source | rtl | win windows . pas каталога размещения Delphi. Фактически виртуальный код - это просто уникальный числовой идентификатор клавиши. Для буквенно-цифровых клавиш О...9 и A...Z виртуальный код совпадает с кодом, возвращаемым функцией ord(X), где х - соответствующий заглавный символ: ord('o'), ord( 'w') и т. д. К сожалению, уникальность кода не обеспечивается для клавиши Enter в зоне дополнительных числовых клавиш, которой присвоен код 13, - как и аналогичной клавише в основной зоне, а также для правых и левых сдвиговых клавиш Shift, Alt и Ctrl. Кроме того, клавиши О...9 и Del в зоне дополнительной клавиатуры сопровождаются уникальным кодом только при активном переключателе NumLock, в противном случае они повторяют коды соответствующих управляющих клавиш. Все остальные клавиши стандартной клавиатуры (за исключением Print Screen, клавиш смещения курсора и Tab, нажатие на которые не передается в обработчики TKeyEvent) имеют постоянно закрепленные за ними числовые коды, позволяющие легко установить факт нажатия или отпускания любой из них.

Поскольку параметр кеу в каждом обработчике определен как параметр-переменная, программист может изменить фактический код клавиши на нужный. Такая возможность может оказаться полезной для фильтрации нажатия каких-либо клавиш. При этом изменение кода происходит в обработчике формы, а в оконный элемент с фокусом ввода будет поступать уже измененный код. Чтобы форма получила событие до передачи его в элемент с фокусом ввода, следует поместить в свойство property KeyPreview: Boolean;

формы значение True.

 17.6.3. Клавиатура в MS-DOS и Windows

Следует заметить, что Windows значительно “строже” относится к использованию клавиатуры, чем MS-DOS. Это может вызывать проблемы при переносе игровых приложений, а также приложений, созданных с помощью FoxPro или Clipper, в среду Delphi.

Если вы захотите сохранить устоявшиеся приемы использования клавиатуры в новой разработке (а я настоятельно рекомендую сделать это), вам, возможно, придется перехватывать сообщения Windows, так как только таким способом программа сможет опознать факт нажатия на системные клавиши Alt, Tab, Shift и т. п. Нажатие на остальные клавиши можно анализировать с помощью перехвата сообщений от клавиатуры в обработчиках Опкеуххх формы при установленном значении True в ее свойство Keypreview. Например, пусть акселератор Alt+X используется в существующей программе для закрытия модального диалогового окна. Чтобы сконструированное вами окно закрывалось по этой команде, напишите для него такой Обработчик события OnKeyDown:

procedure TForm2.FormKeyDown(Sender: TObject;

var Key: Word; Shift: TShiftState) ;

begin

if (Key = ord('X')) and (ssAlt in Shift) then Close

end;

Во многих случаях можно использовать собственные клавиши-акселераторы Windows. К сожалению, такими клавишами снабжаются лишь опции меню, но связанные с ними (опциями) обработчики OnClick выйолняются даже в том случае, когда опция меню не видна (ее свойство visible имеет значение False). Этим можно воспользоваться, чтобы вставить в главное меню окна фиктивные невидимые опции, связав их с нужными акселераторами. Пусть, например, клавиша Buttoni должна “нажиматься” при нажатии Ctrl+S. Поместите на форму главное меню (если его еще нет) и создайте в нем опцию-заголовок с произвольным именем, например, MyButton. В списке свойства Shortcut опции выберите Ctrl+S и установите False в ее свойство visible. Теперь можно связать ее обработчик события OnClick непосредственно с Button1Click или написать такой обработчик:

procedure TForm2.MyButtonClick(Sender: TObject);

begin

ButtonlClick(Self)

end;

И хотя опция MyButton главного меню не видна, нажатие связанных с ней клавиш Ctrl+S вызовет срабатывание нужного обработчика. В этом случае форма может не перехватывать клавиатурный ввод.

Как уже отмечалось, обработчики Опкеуххх не реагируют на нажатие системных клавиш Windows, в том числе - клавиш смещения курсора. Происходит это из-за того, что умалчиваемая оконная функция программы осуществляет стандартную обработку соответствующих сообщений Windows. Оконная функция связывается с каждым программным окном. Ее назначение - осуществлять связь программы с Windows. В оконную функцию главного окна программы Windows помещает сообщения о наступлении того или иного события, в том числе - о нажатии на клавишу. Оконная функция главного окна передает это сообщение оконной функции окна с фокусом ввода (см. ниже п. 17.6.4), а та, в свою очередь - функции сфокусированного оконного компонента. Чтобы получать все адресованные программе сообщения Windows, необходимо использовать метод HookMainwindow глобального объекта-программы Application или его обработчик события OnMessage. Единственным параметром обращения к методу Application. HookMainwindow является имя функции типа

TWindowHook = function(var Message: TMessage): Boolean of object;

которая будет получать сообщение Message. Возвращаемый ею результат и возможные изменения сообщения Message игнорируются. Фактически функция получает сообщение параллельно с иконной функцией и не может воздействовать на обработку сообщения. В

отличие от этого обработчик Application. OnMessage

type

TMsg = packed record

hwnd: HWND; message: UINT; wParam: WPARAM; IParam: LPARAM;

time: DWORD; pt: TPoint;

end;

TMessageEvent = procedure (var Ms.g: TMsg;

var Handled: Boolean) of object-property OnMessage: TMessageEvent;

может запретить стандартную обработку сообщения. Для этого ему передается параметр Handled, в который следует установить True, если дальнейшая обработка сообщения не нужна.

В переменных типа TMsg ядро Windows передает программе так называемые сообщения - небольшие пакеты данных, оповещающие программу о наступлении того или иного события, будь то нажатие на клавишу, перемещение мыши или наступление нужного момента времени. Три параметра этого пакета используются следующим образом: Message - код события, wParam и lParam - уточняющие параметры. Для сообщения о нажатии клавиши код Message определен константой wm_KeyDown (256) или (при отпускании клавиши) wm_KeyUp (257), параметр wParam содержит виртуальный код нажатой клавиши, а IParam - дополнительные параметры, такие как количество нажатий клавиши с момента последнего обращения к функции перехвата, признак нажатой и удерживаемой Shift-клавиши и т. п.

Вот как, например, можно использовать клавиши курсора для смещения изображения (квадрата) в компоненте PaintBox:

type

TFormI = class(TForm)

PaintBoxl: TPaintBox;

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

procedure PaintBoxIPaint(Sender: TObject);

private

{ Private declarations }

public .

{ Public declarations }

X, Y: Integer-procedure Hook(var Msg: TMsg; var Handled: Boolean);

end;

procedure TFormI.FormCreate(Sender: TObject);

{Регистрируем обработчик OnMessage в момент создания главного окна программы и устанавливаем начальное положение квадрата} begin

Application.OnMessage := Hook;

X := 100;

Y := 100;

end;

procedure TFormI.Hook(var Msg: TMsg; var Handled: Boolean);

begin

if Msg.Message<>wm_keyDown then //Сообщение от клавиатуры?

Exit; //Нет case Msg.wParam of

vk_Left: dec(X,10); //Смещение влево

vk_Right: inc(X,10);//Смещение вправо

vk Up: dec(Y,10); //Смещение вверх

vk_Down: inc(Y,10); //Смещение вниз end;

Paintboxl.Repaint;

Handled := True; //Блокируем дальнейшую обработку end;

procedure TFormI.PaintBoxIPaint(Sender: TObject);

(Вычерчиваем квадрат со стороной 20 пикселей и центром в точке X, Y} begin

with PaintBoxl.Canvas do

Rectangle(X-10,Y-10,X+10,Y+10)

end;

В Delphi 5 и 6 специальный компонент TApplicationEvents, который существенно упрощает обработку любых сообщений Windows до торр, как они поступят в оконную функцию активной

Для клавиш определены следующие виртуальные коды:

Код

Значение

Клавиша

Код

Значение

Клавиша

vk Back

8

Backspace

vk A..vk Z

65..90

A. .Z

vk Tab

9

Tab

vk LWin

91

Левая Windows

vk Clear

12

[5]

vk RWin

92

Правая Windows

vk Return

13

Enter

vk NumpadO.. vk Numpad9

96..105

[О]..[9]

vk Shift

16

Shift

vk Multiply

106

[*]

vk Control

17

Ctti

vk Add

107

[+]

vk Menu

18

Alt

vk Subtract

109

[-]

vk Pause

19

Pause

vk Decimal

110

[Del]

vk Capital

20

Caps Lock

vk Divide

111

[/]

vk Escape

27

esc

vkFl..vkF12

112..123

Fl..F12

vk Space

32

Пробел

vk Numlock

144

Num Lock

vk Prior

33

Page Up

vk Scroll

145

Scroll Lock

vk Next

34

Page Down

 

186

 

vk End

35

End

 

187

+

vk Home

36

Home

 

188

<

vk Left

37

Курсор влево

 

189

-

vk Up

38

Курсор вверх

 

190

>

vk Right

39

Курсор вправо

 

191

•?

vk Down

40

Курсор вниз

 

192

~

vk Insert

45

Insert

 

219

[

vk Delete

46

Delete

 

220

\

vk 0..vk 9

48..57

0..9

 

221

]

В квадратных скобках указаны клавиши из зоны дополнительных цифровых клавиш.

Учтите, что константы vk_A.. .vk_z и vk_o.. .vk_9 не определены в файле source | rtl | win | windows . pas и следовательно в модуле System, поэтому для них компилятор выдаст сообщение о неизвестном идентификаторе - в этом случае используйте собственные определения констант или их числовые эквиваленты. Замечу также, что с помощью анализа параметра мзд. lParam в обработчике OnMes-заде можно отличить нажатие левых клавиш Alt, Ctrl, Shift от нажатия одноименных правых и нажатие Enter в основной клавиатуре от нажатия Enter в дополнительной.

17.6.4. Фокус ввода

Поскольку клавиатура - одна, а элементов, могущих ее использовать, может быть много, необходимо каким-то способом выделять элемент, которому в данный момент передается клавиатурный ввод. Это выделение достигается передачей элементу фокуса ввода с помощью его метода procedure SetFocus;

Компонент с фокусом ввода имеет значение True в своем свойстве property Focused: Boolean;

Если элемент запрещен к выбору или невидим, его свойство

property CanFocus: Boolean;

имеет значение False.

Фокус ввода передается элементу после щелчка на нем мышью или в порядке выбора его клавишей Tab. Чтобы элемент можно было выбирать этой клавишей, следует установить в его свойство

property TabStop: Boolean;

значение True. Порядок выбора элемента определяется свойством

property TabOrder: Integer;

Delphi следит за уникальностью и непрерывностью значений этого свойства у всех помещенных на форму не запрещенных и видимых в данный момент компонентов. С помощью метода procedure GetTabOrderList(List: TList) ;

можно получить список всех дочерних элементов, выбираемых клавишей Tab.

17.7. МЕХАНИЗМ ДЕЙСТВИЙ ACTION

В Delphi 4...6 введен специальный механизм действий, дающий удобное средство централизованной реакции программы на те или иные действия пользователя. Для реализации действий в страницу Standard палитры компонентов включен специальный компонент

TActionList (CM. П. 18.1.15), а в объект TComponent - свойство Action:

property Action: TBasicAction;

Централизация необходима потому, что подавляющее большинство промышленных программ для Windows содержат два или более интерфейсных элемента, реализующих одно и то же действие. Например, в среде Delphi некоторые команды главного меню дублируются соответствующими пиктографическими кнопками (в принципе любая команда меню Delphi может иметь кнопочный эквивалент).

Компонент TActionList содержит список названий действий и связанных с ними имен подпрограмм, которые эти действия реализуют. Чтобы связать компонент с нужным действием, достаточно раскрыть список его опции Action (этот список содержит имена всех действий во всех компонентах TActionList) и выбрать нужное название. При этом обычно меняется пиктографическое изображение и/или надпись на компоненте, а также связанная с ним оперативная подсказка (Hint). Свойство Action используется только после создания и наполнения списка (списков)

TActionList.

17.8. ИНТЕРФЕЙС DRAG&DROP

Операционная система Windows широко использует специальный прием связывания программ с данными, который называется Drag&Drop (перетащи и отпусти). Такой прием в Проводнике windows используется для копирования или перемещения файлов, а также для запуска обрабатывающей программы. Если, например, файл с расширением doc “перетащить” на пиктограмму WinWord, автоматически запустится текстовый редактор word for windows и в его окне появится текст из этого файла.

В Delphi реализован собственный интерфейс Drag&Drop, позволяющий компонентам обмениваться данными путем “перетаскивания” их мышью. Этот интерфейс определяется двумя свойствами и тремя событиями, доступными каждому видимому компоненту.[В Delphi б события могут дублировать сложные свойства и наоборот. Сложными в данном случае называются свойства, ссылающиеся на внутренние объекты.]

Свойство

TDragMode = (dmManual, dmAutomatic);

property DragMode: TDragMode;

определяет, как будет выполняться весь комплекс действий, связанных С Drag&Drop: dmManual - Вручную (программой); dmAutomatic -автоматически (свойствами и методами компонентов). Значение dmManual означает, что все необходимые для обслуживания интерфейса события генерируются программой, dmAutomatic - события инициируются свойствами и методами компонентов. Во всех случаях программист должен написать обработчики этих событий (см. ниже).

Свойство property DragCursor: TCursor;

определяет вид указателя мыши в момент, когда над компонентом “протаскиваются данные”. Если компонент готов принять данные, он устанавливает в это свойство значение crDrag l3, в противном случае - crNoDrag 0. Установка этих свойств осуществляется автоматически, если DragMode = dmAutomatic. Событие TDragState = (dsDragEnter, dsDragLeave, dsDragMove) ;

TDragOverEvent = procedure(Sender, Source: TObject;

X, Y: Integer; State: TDragState; var Accept: Boolean)

of object; property OnDragOver: TDragOverEvent;

возникает в момент перемещения указателя мыши “с грузом” над компонентом. Здесь sender - компонент, который возбудил событие (обычно это Self - сам компонент-получатель; при ручном управлении механизмом Drag&Drop это может быть не так); source - компонент-отправитель “груза”; х, y - текущие координаты указателя мыши в пикселях клиентской области компонента; State - состояние указателя (dsDragEnter - только что появился на компонентом; dsDragLeave -только что покинул компонент или бьша отпущена кнопка мыши;

dsDragMove - перемещается над компонентом). В параметре Accept обработчик сообщает, готов ли компонент принять данные (т rue - готов).

Событие

TDragDropEvent = procedure(Sender, Source: TObject;

X, Y: Integer) of object;

property OnDragDrop: TDragDropEvent;

означает, что пользователь “бросил” данные на компонент. Параметры обработчика совпадают по назначению с одноименными параметрами OnDragOver.

Наконец, при завершении перетаскивания (вне зависимости от того, приняты данные или нет) возникает событие TEndDragEveht = procedure(Sender, Target: TObject;X, Y: Integer) of objects; property OnEndDrag: TEndDragEvent;

где sender - отправитель данных; Target - получатель данных или nil, если никто не принял “посылку”; X, Y - координаты мыши в момент отпускания левой кнопки.

Чтобы проиллюстрировать использование механизма Drag&Drop, загрузите описанную в гл. 5 учебную программу, установите во всех ее компонентах в свойство DragMode значение dmAutomatic и создайте такой обработчик события OnDragOver для метки:

procedure TfmExample.IbOutputDragOver(Sender, Source: TObject;

X, Y: Integer; State: TDragState;

var Accept: Boolean);

begin

Accept := True;

lbOutput.Caption := (Source as TComponent).Name

end;

Теперь перетаскивание любого компонента на метку IbOutput заставит ее показать имя перетаскиваемого компонента (рис. 17.5).

Рис. 17.5. Метка IbOutput показывает имя перетаскиваемого компонента

Для ручного (программного) управления механизмом Drag&Drop используются следующие методы, доступные любому потомку TControl:

procedure BeginDrag (Immediate: Boolean);

Используется источником для инициализации процесса Drag&Drop. Если Immediate =True, процесс начинается немедленно, в противном случае - после смещения указателя мыши на 5 пикселей в любом направлении

procedure DragDrop (Source: TObject; X, Y: Integer);

Вызывает обработчик события OnDragDrop

procedure EndDrag(Drop: Boolean);

Вызывает обработчик события OnEndDrag и в параметре Drop сообщает о том, были ли приняты данные

17.9. ИНТЕРФЕЙС DRAG&DOCK

В Delphi введена поддержка специального интерфейса Drag&Dock (перетащи и причаль), с помощью которого можно перетаскивать мышью компоненты на новое место. В среде Delphi этот интерфейс используется для настройки кнопок инструментальных панелей (см. гл. 2).

В интерфейсе Drag&Dock участвуют два компонента: принимающий компонент (всегда - потомок TWinControl) и перетаскиваемый компонент (потомок TControl).

Принимающий компонент должен иметь значение True в своем свойстве Docksite. Поскольку Drag&Dock является разновидностью более общего интерфейса Drag&Drop, в TControi введено дополнительное свойство

property DragKind: TDragKind;

type TDragKind = (dkDrag, dkDock) ;

с помощью которого различаются способы использования мыши:

для Drag&Drop (dkDrag) или для Drag&Dock (dkDock). И у перетаскиваемого компонента, и у компонента-приемника эти свойства должны иметь значения dkDock.

Количество установленных на форме перетаскиваемых компонентов (Т. С. компонентов, у которых DragKind=dkDock И DockSite=False) Определяется свойством DockClientCount, а их список хранится в индексированном свойстве DockClients.

Для реализации Drag&Dock в класс TControl введены такие дополнительные свойства и события.

property AutoSize: Boolean;

Разрешает (True) или запрещает (False) оконному компоненту менять свои размеры автоматически в зависимости от количества и размеров содержащихся в нем дочерних компонентов. Свойство

property FloatingDockSiteClass: TWinControlClass;

определяет класс окна, в которое будет погружен дочерний элемент вне границ оконного элемента. Неоконные компоненты могут не только перетаскиваться в оконные компоненты-приемники, но и покидать их. После “отчаливания” от компонента-приемника неоконные элементы автоматически окружаются окном, тип которого содержит свойство FloatingDockSiteClass. По умолчанию это окно содержит уменьшенный по высоте заголовок и системную кнопку закрытия. В свойстве

property DockOrientation: TDockOrientation;

type TDockOrientation = (doNoOrient,doHorizontal,doVertical);

можно установить (или получить) ориентацию, которую будет иметь “причаливаемый” компонент в окне родителя: doNoOrient -сохраняется исходная ориентация перемещаемого компонента; do-Horizontal (dovertical) - компонент будет иметь горизонтальную (вертикальную) ориентацию. С помощью свойства

property LRDockWidth: Integer;

можно получить ширину последнего перемещенного компонента, который расположился горизонтально, а с помощью

property TBDockHeight: Integer;

- высоту последнего вертикально расположенного компонента.

Свойства

property UndockHeight: Integer; property UndockWidth: Integer;

определяют соответственно высоту и ширину последнего “отчалившего” компонента. Свойство

property Constraints: TSizeConstraints;

с помощью объекта класса TSizeConstraints накладывает ограничения на возможные размеры “причаливаемого” компонента (задает максимальные и минимальные величины для высоты и ширины).

События

property OnDockDrop: TDockDropEvent;

property OnDockOver: TDockOverEvent;

type TDockOverEvent = procedure(Sender: TObject; Source:

TDragDockObject; X, Y: Integer; State: TDragState;

var Accept:

Boolean) of object;

аналогичны событиями OnDragDrop и OnDragOver (CM. П.17.7). Co6ытие

property OnGetSiteInfo: TGetSiteInfoEvent;

возникают перед событием OnDragDrop. Его обработчик должен сообщить объекту TDragDockObject, который автоматически связывается с перемещаемым объектом, некоторую дополнительную информацию (размеры, которые будет иметь принимаемый объект, будет ли он погружен в “плавающее” окно и т. п.). Наконец, событие

property OnUnDock: TUnDockEvent;

type TUnDockEvent = procedure(Sender: TObject; Client: TControl;

var Allow: Boolean) of object;

возникает при “отчаливании” неоконного компонента от своего родителя. Обработчик этого события должен поместить в Allow значение True, если компонент client может покинуть границы своего владельца sender.

Все указанные события обрабатываются автоматически, если оба компонента (клиент и сервер) содержат значение dmAutomatic в своем свойстве DragMode.

Чтобы познакомиться в действии с технологией Drag&Dock, поместите на пустую форму панель трапе! и кнопку TButton, установите для панели значение True в свойство Docksite, установите для

обоих компонентов Значение dkDock в свойстваа DragKind И dmAutomatic в свойства DragMode. После запуска программы перетащите кнопку на панель, а затем стащите ее обратно.

17.10. ПОДДЕРЖКА СПРАВОЧНОЙ СЛУЖБЫ

Все видимые элементы имеют свойства

property Hint: String;

property ShowHint: Boolean;

регулирующие появление и содержание ярлычка - небольшого справочного окна возле элемента, на котором остановился курсор. Ярлычки существенно облегчают начинающему пользователю знакомство с программным продуктом. Введение механизма ярлычков во все видимые компоненты легко решает проблему создания дружественного программного интерфейса в современном стиле.

Чтобы компонент смог показать ярлычок, нужно поместить текстовую строку в его свойство Hint и присвоить свойству showHint значение True. Обычно ярлычок содержит максимально лаконичный текст, чтобы не отнимать слишком большую площадь экрана. Вы можете дополнить этот текст развернутым сообщением в любом компоненте, который способен отображать текст. Как правило, это панель статуса, занимающая нижнюю часть формы. Чтобы отобразить <<длинное” сообщение, его нужно прежде всего поместить в строку Hint сразу после “короткого” и отделить обе части символом “[”.

Например:

MyControl.Hint := 'Подсказка!Развернутое сообщение';

Далее, необходимо в самом начале программы (обычно в обработчике события Oncreate главной формы) указать программе метод, который будет обрабатывать событие onHint. Это событие возникает в момент появления ярлычка и предназначено для отображения длинного сообщения, которое метод-обработчик может получить в свойстве Hint глобального объекта Application.

Например:

type

TFormI=class(TForm) pnStatus: TPanel;{Панель для отображения длинной части Hint}

public

// Объявляем метод-обработчик события OnHint:

procedure ShowLongHint(Sender: TObject);

end;

procedure TFormI.ShowLongHint(Sender: TObject);

{Этот обработчик помещает на панель pnStatus длинную часть Hint}

begin

pnStatus.Caption := Application.Hint;

end;

procedure TFormI.FormCreate(Sender: TObject) ;

// Метод определяет свойство OnHint объекта-программы

begin

Application.OnHint := ShowLongHint;

end;

Обратите внимание: обработчиком события OnHint должен быть метод класса, а не обычная процедура. Вот почему в предыдущем примере в секцию public класса TForm1 вставлено описание метода

ShowLongHint.

И еще одно замечание. Обычно свойство Hint у компонента устанавливается на этапе конструирования формы. В этом случае вы можете создать только однострочный ярлычок. Если же установить свойство Hint на этапе прогона, вы сможете вставить в символьную строку разделители EOLN и таким способом создать многострочный ярлычок:

bbClose.Hint := 'Эта кнопка'#13'завершает работу '#13'программы';

Следующие свойства глобального объекта-программы Application регулируют цвет и время появления ярлычка:

property HintColor: TColor;

Определяет цвет фона ярлычка

property HintHidePause: Integer;

Определяет длительность показа ярлычка в миллисекундах. По умолчанию равно 2500 (2,5 секунды). Чтобы ярлычок вообще не убирался, установите значение -1

property HintPause: Integer;

Определяет паузу в миллисекундах после остановки указателя мыши и перед появлением ярлычка. По умолчанию равно 500

property HintShortPause: Integer;

Определяет паузу перед появлением ярлычка при переходе с одного компонента с заданным свойством Hint на другой такой же. По умолчанию равно 50

Все видимые компоненты содержат свойство

property HelpContext: Integer;

с помощью которого компонент привязывается к контекстно-чувствительной справочной службе. В это свойство следует поместить идентификатор раздела Help-файла, который (раздел) будет автоматически показываться в окне встроенной помощи после нажатия кнопки F1.

У многих видимых компонентов имеется свойство

property PopupMenu: TPopupMenu;

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

17.11. ПОДДЕРЖКА СОМ

Модель компонентных объектов СОМ (Component Object Model) представляет собой технологию обмена объектами между разными приложениями и даже между разными сетевыми машинами. Эта технология усиленно развивается Microsoft и в перспективе может привести к тому, что ваша программа сможет использовать объект (напомню, что объект - это фрагмент исполняемого кода), установленный на машине, находящейся в другой части света и не относящейся к тому же классу, что и ваша машина, т. е. написанный на другом языке программирования и реализованный другим набором машинных инструкций!

В основе СОМ лежат те же идеи, что и в OLE, с той разницей, что СОМ-сервер может выполнять обработку СОМ-клиента на машине сервера.

Разумеется, и сервер, и клиент в технологии СОМ могут быть установлены на одной и той же машине, однако в OLE это фактически является обязательным требованием. Если клиент и сервер выполняются на разных машинах, реализуется распределенный вариант СОМ - DCOM (Distributed Component Object Model).

В Delphi включены средства поддержки СОМ как в виде готовых компонентов (например, DCOMConnection), так и на уровне класса TComponent, т. е. относящиеся ко всем компонентам Delphi.

Свойство этого класса

property ComObject:IUnknown;

возвращает интерфейс СОМ-объекта, если данный компонент поддерживает технологию СОМ. Если это не так, обращение к свойству

возбудит исключительную ситуацию EComponentError.

Свойство

property VCLComObject: Pointer;

предназначено для внешнего использования (т. е. для экспорта СОМ-объекта) и поставляет ссылку на СОМ-объект Delphi.

17.12. СВОЙСТВА РАЗНОГО НАЗНАЧЕНИЯ

Узнать текущее состояние любого управляющего элемента на этапе прогона программы можно с помощью свойства

type TControlState = set of (csLButtonDown, csClicked, csPalette, csReadingState, csAlignmentNeeded, csFocusing, csCreat-ing, csCustomPaint, ceDestroyingHandle);

property ControlState: TControlState;

класса TControl.

Элементы множества TControlState имеют следующий смысл:

csLButtonDow

Над элементом была нажата и еще не отпущена левая кнопка мыши

n csClicked

То же, что csLButtonDown, но устанавливается, если стиль компонента (см. ниже) содержит флаг csClickEvents и означает, что нажатие кнопки интерпретируется как щелчок

csPalette

Элемент или его родитель получил сообщение

WMPALETTCHANGED

csReadingState

Элемент читает данные из потока

csAlignmentNeeded

Элемент нуждается в перерисовке, т. к. изменилось его свойство Alignment

csFocusing

Программа пытается передать элементу фокус ввода

csCreating

Элемент и/или его родительские и дочерние элементы находятся в стадии создания. Флаг очищается после завершения процесса

csCustomPaint

Элемент перерисовывается

csDestroyingHandle

Разрушается Windows-дескриптор элемента

Свойство

type TControlStyle = set of (csAcceptsControls, csCaptureMouse, csDesignInteractive, csFramed, csClickEvents, csSetCaption, csOpaque, csDoubleClicks, csFixedWidth, csFixedHeight, csNoDesignVisible, csReplicatable, csNoStdEvents, csDisplayDraglmage, csReflector, csActionClient, csMenuEvents) ;

property ControlStyle: TControlStyle;

содержит стилевые флаги элемента, имеющие такой смысл:

csAcceptsControls

Элемент может стать владельцем дочернего элемента в технологии Drag&Dock

csActionClient

Элемент может участвовать в централизованном действии

csCaptureMouse

Элемент будет получать все сообщения от мыши, даже если ее указатель выйдет из его границ

csClickEvents

Элемент может воспринимать щелчок мыши

csDesignInteractive

Элемент воспринимает щелчок правой кнопкой мыши на этапе конструирования формы

csDisplayDragImage

Элемент способен менять свое изображение при протаскива-нии над ним “груза” в технологии Drags Drop

csDoubleClicks

Элемент может воспринимать двойной щелчок мыши

csPixedHeight

Элемент имеет фиксированную высоту

csFixedWidth

Элемент имеет фиксированную ширину

csFramed

Элемент имеет трехмерную рамку

csNoDesignVisible

Элемент не виден на этапе конструирования формы

csNoStdEvents

Элемент не реагирует на стандартные события от мыши или клавиатуры

csOpaque

Элемент закрашивает всю свою клиентскую область

csReflector

Элемент способен получать диалоговые сообщения windows, сообщения, связанные с получением/потерей фокуса ввода и изменением размеров.

csReplicatable

Используется для компонентов АсtiveX

csSetCaption

Элемент способен отобразить свой образ с помощь метода PaintTo Элемент будет изменять свой заголовок при изменении своего свойства Name

Пара свойств класса Twincontrol

type TImeMode = (imDisable, imClose, imOpen, imDontCare, im-

SAlpha, imAlpha, imHira, imSKata, imKata, imChinese, imSHanguel, imHanguel);

property ImeMode: TImeMode;

И

type TImeName = String;

property ImeName: TImeName;

определяют режим работы и имя специального редактора IME (Input Method Editor) для предварительной обработки клавиатурного ввода в случае использования азиатских языков. С помощью свойства

type TBiDiMode = (bdLeftToRight, bdRightToLeft, bdRightToLeft-NoAlign, bdRightToLeftReadingOnly);

property BiDiMode: TBiDiMode;

класса TControl программа может задать порядок чтения текста, расположение вертикальных полос прокрутки и изменение свойства Alignment так, чтобы учесть особенности арабского и подобного письма слева направо.

Hosted by uCoz