Использование методов-сообщений для вызова корреспондирующих методов
Использование методов-сообщений
Некоторые события в классе TControl помимо корреспондирующих методов включают и объявление методов сообщений, с помощью которых осуществляется вызов корреспондирующих методов. Для этого следует объявить идентификатор пользовательского сообщения и метод сообщения в объявляемом классе. Далее следует представить реализацию метода сообщения, код которого должен включать обращение к корреспондирующему методу. Далее следует посылать сообщение любым известным способом.
Const WM_USER1=WM_APP; // Идентификатор номера сообщения Type
Type
TNumMemo=Class(TMemo)
Protected // Дополнительно объявляем метод сообщения
Procedure WMNumStr(Var Msg: TMessage); Message WM_USER1;
Реализация метода сообщения может быть очень проста:
Procedure TNumMemo.WMNumStr(Var Msg: TMessage);
Begin
Form1.NumMemo.DoNumStr(Msg.wParam);
End;
Теперь вызов корреспондирующих методов может быть заменен посылкой сообщений. Приведем несколько различных вариантов посылки сообщения о возникновении события.
Procedure TForm1.FormKeyDown(Sender: TObject; Var Key: Word;
Shift: TShiftState);
Begin
Case Key Of
VK_DOWN: If (NumMemo.NumStr<NumMeino.Lines.Count+1) Then Nuni-Memo.Perfornt(WM_USER1, 1, 0);
VK_UP: If (NumMemo.NumStr>1) Then
SendMessage(NumMemo.Handle, WM_USER1, -1, 0);
VK_RETURN: PostMessage(NumMemo.Handle, WM_USER1,1, 0);
End;
End;
Обработчики событий
События — это свойства процедурного типа, предназначенные для создания пользовательских реакций на те или иные входные воздействия. Присвоить такому свойству значение — это указать адрес метода, который будет вызываться в момент наступления события.
Для создания обработчика событий необходимо дважды щелкнуть мышью по соответствующему событию компонента на странице Events инспектора объектов. Delphi создаст заготовку обработчика события, включая объявление метода в классе TForm и его реализацию с операторными скобками Begin End.
События имеют разные типы в зависимости от происхождения и предназначения.
Фактически процедуры-обработчики событий различаются набором параметров, при этом общим для всех является параметр Sender, указывающий на объект-источник события. Когда происходит событие, связанное с некоторым обработчиком событий, этот обработчик событий получает сообщение для объекта, который породил это событие. Это сообщение передается обработчику события через параметр Sender.
Чтобы быть совместимым с событием данного типа, обработчик события должен иметь тоже число и тип параметров, что и у указанного типа.
есть возможность выбрать следующие действия:
• проигнорировать событие
В этом случае поведение объекта будет определяться обработчиком события по умолчанию и его можно переопределить;
• перехватить событие (trap the event)
Тогда необходимо написать собственный обработчик события, изменяющий поведение объекта, принятое по умолчанию.
Обработчики уведомительных событий
Самый простой тип стандартного события TNotifyEvent является уведомительным и не имеет других параметров, кроме Sender, указывающего на объект, вызвавший событие. Тип объявлен в модуле Classes следующим образом:
Type TNotifyEvent=Procedure(Sender: TObject) Of Object;
Наиболее часто используемое событие этого типа OnClick — щелчок мышью по компоненту предусмотрен у большинства компонентов управления. В простейшем случае обработчик этого события может выглядеть следующим образом:
Procedure TForm1.FormClick(Sender: TObject);
Begin
ShowMessage(‘Щелчок мышью по форме!’);
End;
Обработчики специфических событий
При возникновении специфического события, операционная система передает не только уведомление (сообщение) о нем, но и некоторую связанную с ним информацию. Например, когда пользователь щелкает мышкой (событие OnMouseDown), операционная система обрабатывает это событие и передает сообщение в окно, которое должно обработать данное событие. При этом дополнительная информация включает координаты нахождения мыши в момент щелчка и сведения о том, какая клавиша мыши была нажата. Это событие имеет тип TMouseEvent, который объявлен в Delphi следующим образом:
Type TMouseEvent Procedure Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer) Of Object;
Делегирование событий
Поскольку события — это свойства объекта, за которыми, естественно, стоят поля, то значения этих полей можно изменять во время выполнения программы. Таким образом, в любой момент можно присвоить событие одного объекта другому объекту, имеющему однотипное событие. Поскольку значениями являются указатели на методы-обработчики событий, то фактически присваиваются (делегируются) способы реакций на однотипные события. Синтаксически это выглядит следующим образом:
<oбъeкт1>.<coбытиe>.=:<oбъeкт2>.<coбытиe>;
Когда необходимость в делегировании события отпадает, то достаточно присвоить (делегировать) событию «пустой» указатель:
<обьект>.<событие>:=Nill;
Например:
Objl:=T1Class.Create;
Obj2:=T2Class.Create;
Obj1.OnMyEvent:=Obj2.SetValue1; // Делегирование первого метода
Obj1.OnMyEnent:=Obj2.SetValue2; // Делегирование второго метода
Obj1.OnMyEnent:=Nil; // Отключение всех обработчиков
Напомним, что как в этом примере, так и повсюду в Delphi за свойствами-событиями стоят поля, являющиеся указателями на метод. Таким образом, при делегировании этим полям можно присвоить указатели на методы других классов. Главное, они должны быть одного типа.
Переопределение стандартных событий
События, предусмотренные в Delphi и наследующие наиболее общие случаи, возникающие в Windows, называются стандартными событиями. Как правило, поля для хранения значений этих событий защищены от разработчиков, т.е. нет возможности подключать обработчики к ним. При этом вызовы обработчиков стандартных событий происходят внутри методов, обрабатывающих сообщения Windows.
Имеется две категории стандартных событий:
• События, определенные для всех средств управления. Эти события определены в классе TControl. Список подобных событий включает восемь наименований: OnClick, OnMouseMove, OnDblClick, OnMouseDown, OnMouseUp.
Эти события доступны во всех элементах управления. Стандартные события имеют корреспондирующие защищенные динамические методы. Так динамический метод Click вызывается для обработки события OnClick.
• В дополнение к ним определены стандартные события для стандартных средств управления Windows, которые являются уже наследниками класса TWinControl. Список этих событий включает пять наименований и приведен
Эти события также имеют корреспондирующие методы.
OnEnter — Элемент управления получает фокус.
OnKeyDown — Пользователь нажимает клавишу.
OnKeyPress — Пользователь нажимает символьную клавишу.
OnKeyUp — Пользователь отпускает нажатую клавишу.
OnExit — Элемент управления теряет фокус.
У пользователя есть следующие возможности переопределения событий:
• Можно переопределить событие в разделе с большей видимостью с целью сделать его доступными во время разработки и выполнения программы.
Для того, чтобы сделать событие доступным во время выполнения и разработки программы, следует объявить его повторно в разделе Public или Published класса-потомка. Синтаксически это выглядит следующим образом:
Type
<имя класса>=Сlass(<класс-предок>) Published
Property <имя события>// Переопределение события
End;
В самой Delphi подобное переопределение сделано неоднократно. Например, в модуле Controls объявлен класс TControl, включающий событие OnClick, пример объявления которого в разделе Protected был приведен ранее.
Переопределение события изменяет только его уровень защиты и не изменяет стандартной реакции на это событие.
• Можно переопределить корреспондирующий динамический метод с целью включения в его код действий — общих для всех экземпляров этого класса.
Для изменения стандартной реакции на события всех компонентов одного класса следует сделать замещение корреспондирующего защищенного динамического метода в классе-потомке. При этом следует вызывать унаследованный обработчик.
Type
<имя класса>=Сlass(<класс-предок>)
Protected
Procedure <метод>; Override; // Замещение метода End;
Procedure <имя класса>.<метод>; // Реализация замещающего метода Begin
Inherited <метод>; // Вызов наследуемого обработчика
<дополнительный код> // Добавление новых реакций
End;
Таким образом, чтобы изменить корреспондирующий метод события, необходимо указать, когда вызывается наследованное поведение, а когда -новое действие.
• Переопределение стандартного события с целью изменения типа события потребует объявления в классе нового поля нужного типа, переопределения корреспондирующего метода или объявление нового, а также создание их реализации. Принципиально это возможно. При этом доступ к переопределенному событию возможен с помощью привидения типов. Вопрос заключается в целесообразности.