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


Компонентами в Delphi называются потомки класса TComponent. В этой главе описываются общие свойства, методы и события компонентов. В остальных разделах книги при описании конкретного компонента эти свойства уже не упоминаются. Следует учесть, что все они относятся в основном к классам-родоначальникам TObject, TPersistent, TComponent и TControl.
Некоторые из них описаны в секциях protected этих классов и могут быть недоступны своим потомкам. Поэтому для получения полного набора методов, свойств и событий конкретного компонента необходимо обращаться к встроенной справочной службе Delphi.
ИЕРАРХИЯ КОМПОНЕНТОВ
Все компоненты 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 и не оконными компонентами.
ИМЕНА И СОБСТВЕННИКИ КОМПОНЕНТОВ
Класс 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 предназначены следующие методы:

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


Класс 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 Perform(Msg, WParam: Word; LParam: Longint): Longint;
Параметры обращения к методу соответствуют параметрам вызова оконной функции: Msg - код сообщения; WParam, LParam - уточняющие параметры.
ПОЛОЖЕНИЕ, РАЗМЕРЫ И ОФОРМЛЕНИЕ КОМПОНЕНТОВ
Положение и размеры компонента определяются четырьмя его свойствами (в пикселях):
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 хранит четырехбайтное значение, каждый байт которого (слева направо, т. е. от старшего к младшему) имеет следующее назначение:

  • 1 - указатель формата цвета (см. ниже);
  • 2, 3, 4 - интенсивность соответственно синей, зеленой и красной

составляющих.
Например, значение $00000000 определяет черный цвет, $00ff0000 -чистый синий цвет, $00ffffff - белый цвет и т. д.
Старший байт указывает, как используются остальные байты значения. Если он равен нулю, они определяют RGB-цвет так, как это описано выше. Если старший байт равен 1, три оставшихся байта определяют номер одной из 65536 возможных логических палитр (второй байт в этом случае игнорируется). Наконец, если старший байт равен 2, младшие определяют относительный цвет: в этом случае Windows отыскивает в текущей логической палитре ближайший к указанному цвет и использует его для заливки компонента. Другие значения старшего байта игнорируются (точнее, игнорируются старшие 5 разрядов этого байта; самый старший бит, если он равен 1, определяет черный цвет независимо от значений остальных 31 разрядов).
Чтобы разнообразить унылые серые окна программы, соответствующие стандартным формам Delphi, я иногда использую значение $00AAffff, определяющее бледно-желтый цвет (в свойство color можно вводить значения в виде десятичных или шестнадцатеричных чисел). Получить шестнадцатеричное значение того или иного цвета вам поможет несложная программа, окно которой показано на С ее помощью можно выбрать цвет в окне компонента TColor-Dialog (см. дальше п. 17.5.4) и получить его шестнадцатеричное представление или ввести шестнадцатеричное число и увидеть соответствующий ему цвет. Положите на пустую форму две панели - они будут наглядно демонстрировать цвет, выбранный с помощью TCoiorDialog (левая панель), и цвет, заданный с помощью 16-ричной константы (правая панель). Установите в свойство Align панели Panel1. Значение alRight, а в такое же свойство Рапе12 - alClient.

  1. На левую панель положите кнопку TButtcni и диалог TCoiorDialog (этот компонент находится на странице Dialogs палитры компонентов). В значение caption кнопки поместите строку. Выбор цвета.
  2. На правую панель положите редактор TEdit и кнопку TButton. В свойство charCase редактора поместите значение ecupper-case - это заставит компонент преобразовывать вводимые в нем буквы к заглавным и упростит дальнейший их анализ. В Caption кнопки поместите Ввод константы.
  3. Напишите такой обработчик события 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 введены специальные свойства, управляющие трехмерным эффектом, создаваемым такими кромками:

В версиях 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) оконному компоненту автоматически изменять свои размеры в зависимости от количества и размеров содержащихся в нем неоконных компонентов.

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


При перемещении указателя мыши по экрану он может менять свою форму в зависимости от свойства Cursor компонента, над которым он расположен в данный момент:
property Cursor: TCursor;
type TCursor = -32768..+32767;
В практике программирования часто возникает необходимость изменения формы указателя для всех окон программы. Например, при выполнении достаточно длительного по времени процесса указатель мыши часто принимает вид crHourGlass, а после завершения процесса - восстанавливает свой первоначальный вид. Чтобы изменить форму указателя для всех окон программы одновременно, используется свойство cursor у глобального объекта screen, который автоматически создается для каждой программы:
Screen.Cursor := crHourGiass;
..... //Делаем длительную работу
Screen.Cursor := crDefault; // Восстанавливаем начальную
// форму указателя
Программист может создать и использовать нестандартный указатель. При этом он должен:

  • с помощью редактора изображений Delphi создать изображение указателя и разместить это изображение в ресурсном файле программы;
  • в работающей программе сначала загрузить указатель из ресурсного файла с помощью функции LoadCursor и зарегистрировать его в списке cursors объекта screen, а уже только после этого назначать нестандартный указатель свойствам cursor компонентов или экрана.

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

  • Выберите опцию меню Tools | image Editor, чтобы загрузить редактор изображений Delphi.
  • В окне редактора сначала выберите File | New | Resource File, а затем - Resource | New | Cursor. Окно редактора к этому моменту должно иметь вид, показанный на С помощью опции Resource | Rename обязательно измените стандартное имя ресурса cursorl на любое другое, например, mycursor. Вы можете даже написать прежнее имя Сursor1, но изменить умалчиваемое имя ресурса нужно обязательно, иначе функция LoadCursor не сможет извлечь указатель из ресурсного файла (это имя должно состоять из заглавных букв).
  • Дважды щелкните по ресурсу в списке ресурсов или выберите опцию Resource | Edit - на экране появится окно редактора с двумя пустыми полями, обведенными красными рамками. Левое поле предназначено для показа создаваемого указателя в крупном масштабе, правое показывает его в натуральную величину.
  • Выберите инструмент в форме окружности в левой части окна редактора, нажмите и удерживайте клавишу Shift, чтобы получилась правильная окружность, подведите указатель мыши в виде крестика несколько правее и ниже верхнего угла левого поля редактора, нажмите левую кнопку мыши и, удерживая кнопку и клавишу Shift нажатыми, переместите указатель несколько левее и выше правого нижнего угла поля, после чего отпустите кнопку и клавишу (см. на этом рисунке выбранный инструмент имеет вид вдавленной кнопки).
  • Щелкните мышью по заголовку untitiedi.res окна со списком ресурсов (или закройте окно с изображениями указателя кнопкой в его правом верхнем углу) и с помощью File | save сохраните ресурсный файл под именем cursor, после чего закройте редактор изображений.
  • Создайте новый проект с пустой формой и напишите такой обработчик события OnCreate для формы Form1:

{$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 включительно заняты стандартными указателями, показанными на (индексы -5 и -1 соответствуют указателю crNone), а индекс 0 всегда связан со стандартным указателем Windows ^ и не может переопределяться.
РЕАКЦИЯ НА СОБЫТИЯ ОТ МЫШИ И КЛАВИАТУРЫ
События от мыши
Для большинства видимых компонентов определен набор обработчиков событий, связанных с мышью:
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.
События от клавиатуры
События от мыши получают любые потомки 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.
Клавиатура в 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;

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика