- •9 Разработка компонентов в среде Delphi
- •9.1. Выбор класса-предка
- •9.1.1. Класс tControl
- •9.1.4. Класс tCustomControl
- •9.2. Создание модуля компонента и тестового приложения
- •Разработка тестового приложения
- •9.3.1. Простые свойства
- •9.3.6. Массив свойств
- •9.3.7. Перекрытие и переопределение свойств
- •9.3.8. Создание событий
- •9.3.9. Создание методов
- •Что такое событие? в чем отличие создания свойства от события?
9.3.6. Массив свойств
Определитель Index позволяет разным свойствам иметь один и тот же метод доступа. Его описание состоит из директивы index и последующей за ней константой целого типа в промежутке от -2147483647 до 2147483647. Если у свойства есть определитель Index, то определители read и write должны ссылаться на методы, а не на поля. Например:
type
TRectangle = class private
FCoordinates: array[0..3] of Longint;
function GetCoordinate(Index: Integer): Longint;
procedure SetCoordinate{Index: Integer; Value: Longint); public
property Left: Longint index 0 read GetCoordinate
write SetCoordinate; property Top: Longint index 1 read GetCoordinate
write SetCoordinate; property Right: Longint index 2 read GetCoordinate
write SetCoordinate; property Bottom: Longint index 3 read GetCoordinate
write SetCoordinate;
end;
Обращение к свойству, определенному с директивой index, например,
Rectangle.Right := Rectangle.Left + 100;
{Rectangle: TRectangle}
автоматически преобразуется к вызову метода,
Rectangle.SetCoordinate (2, Rectangle.GetCoordinate(0) + 100);
9.3.7. Перекрытие и переопределение свойств
Описание свойства без указания типа называется перекрытием свойства. Самый простой способ перекрытия состоит в использовании зарезервированного слова property и идентификатора — имени свойства. Данный способ используется для смены видимости свойства.
Перекрытия свойств могут содержать директивы read, write, stored, default и nodefault. Перекрытие может заменить существующие наследуемые определители доступа, добавить недостающие, увеличить видимость свойства, но оно не может удалить существующий определитель или уменьшить видимость свойства. Следующий пример демонстрирует использование перекрытия свойств:
type
TAncestor = class
protected
property Size: Integer read FSize; property Text: String read GetText write SetText; property Color: TColor read FColor write SetColor stored False;
...
end;
TDerived = class(TAncestor)
...
protected
property Size write SetSize; published property Text; property Color stored True default clBlue;
end;
Перекрытие свойства Size добавляет определитель write, что позволяет редактировать свойство, а перекрытие свойств Text и Color меняет их видимость с protected на published. Перекрытие свойства Color указывает, что оно должно быть сохранено, если его значение отлично от clBlue.
Переопределение свойства включает указание его типа, оно скрывает наследуемое свойство. Это означает, что создается новое свойство с тем же именем, что и у предка. Любое описание свойства, которое содержит указание типа, должно быть завершенным и включать в себя как минимум один определитель доступа:
type TAncestor = class
property Value: Integer read Methodl write Method2; end;
TDescendant = class(TAncestor)
property Value: Integer read Method3 write Method4; end;
9.3.8. Создание событий
Событие — это любое происшествие, вызванное вмешательством пользователя, операционной системы или логикой программы. Событие связано с некоторым программным кодом, отвечающим на это происшествие. Совокупность события и кода, выполняющегося в ответ на это событие, называется свойством-событием и реализуется в виде указателя на некоторый метод. Метод, на который указывает это свойство, называется обработчиком события.
Свойства-события являются не более чем указателями на методы. В модуле Controls.pas определены стандартные свойства-события.
Описание свойства-события начинается с описания нового типа, который представляет собой процедуру, одним из параметров которой, является Sender типа TObject, а директива of object делает эту процедуру методом:
TMouseMoveEvent = procedure(Sender: TObject; Shift: TShiftState; X, Y: Integer) of object;
Когда происходит какое-либо событие, например, перемещение мыши, в систему Win32 посылается соответствующее сообщение, в нашем случае WM_MOUSEMOVE. Система Win32 передает это событие элементу управления, для которого оно предназначено и на которое он должен тем или иным способом ответить. Элемент управления может ответить на это событие, сначала проверив наличие кода, предусмотренного для выполнения. Для этого он проверяет, ссылается ли свойство-событие на какой-либо код. Если да, то элемент выполняет этот код, называемый обработчиком события. Операция по определению наличия метода, связанного с событием-свойством, возлагается на метод диспетчеризации. Эти методы объявляются как защищенные методы того компонента, которому они принадлежат.
Описание свойства-события состоит из двух частей: во-первых, событие требует внутреннего поля данных, которое используется для хранения указателя на метод; во-вторых, создается соответствующее свойство, которое во время проектирования дает возможность присоединения обработчиков событий:
TControl = class(TComponent) private
FOnMouseMove: TMouseMoveEvent; {внутреннее поле события} procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
protected
procedure MouseMove(Shift: TShiftState; X, Y: Integer);
dynamic; {метод диспетчеризации}
property OnMouseMove: TMouseMoveEvent read FOnMouseMove
write FOnMouseMove;
end;
Метод диспетчеризации определяет, существует ли свойство-событие на какой-нибудь метод, и если это так, то передает управление соответствующей процедуре:
procedure TControl.MouseMove(Shift: TShiftState; X, Y: Integer); begin
if Assigned (FOnMouseMove) then FOnMouseMove (Self, Shift, X, Y) ; end;
Чтобы обеспечить возможность переопределения обработки события, необходимо перехватить возникшее событие, обработать его стандартным образом и передать управление методу диспетчеризации:
procedure TControl.WMMouseMove(var Message: TWMMouseMove); begin inherited; if not (csNoStdEvents in ControlStyle) then
{включение csNoStdEvents во множество ControlStyle заставляет игнорировать стандартные события мыши, клавиатуры. Этот флаг позволяет ускорить запуск приложения, если оно при этом не нуждается в обработке этих событий} with Message do MouseMove(KeysToShiftState(Keys), XPos, YPos) ; end;