Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Использование и создание визуальных компонент 6....doc
Скачиваний:
4
Добавлен:
08.07.2019
Размер:
236.54 Кб
Скачать

6.4.2 Определение событий

Формально C++Builder определяет событие как типизированный указатель на метод в специфическом экземпляре класса:

<тип> (_closure * <имя метода>) (<список параметров>)

Для разработчика компонент closure представляет собой некоторую программную заглушку: когда пользователь определяет реакцию на некоторое событие, место заглушки занимает его обработчик, который вызывается вашей программой при возникновении этого события.

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

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

void _fastcall TFormI::EditlKeyPress

(TObject *Sender, char SKey) {

Key = UpCase(Key) ;

)

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

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

При разработке компонент нужно учитывать следующие аспекты обработчиков событий:

• Прикладные программисты не обязаны обрабатывать события. Различные события возникают практически постоянно при работе любого приложения Windows. Простое смещение курсора по компоненте вызывает передачу многочисленных сообщений Windows данной компоненте о передвижении мыши, которые компонента транслирует в события OnMouseMove. Если поведение компоненты не зависит от манипуляций мышью, то в большинстве случаев программа просто не обращает внимание на такие события.

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

6.4.2.3 Стандартные события

Все компоненты VCL наследуют большинство общих сообщений Windows стандартные события. Такие события встроены в защищенные секции компонент, поэтому пользователи не могут подсоединять к ним свои обработчики.

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

OnClick______OnDragDrop___OnEndDrag____OnMouseMove

OnDblClick____| OnDragOver___| OnMouseDown | OnMouseUp

В дополнение к этим событиям, оконные компоненты наследуют от базового абстрактного класса TWinControl еще и следующие стандартные события:OnEnter OnKeyDown OnKeyPress

OnKeyUp OnExit

Чтобы стандартные события вашей компоненты были видимы Инспектору объектов на стадии проектирования или во время выполнения программы, вы должны переопределить свойства событии в секции public или published. Листинг 6.9 показывает, как сделать стандартное событие OnClick видимым.

class TMyControl : public TCustomControl {

_published:

_property OnClick; // OnClick стало видимым Инспектору };

Листинг 6.9. Переопределение стандартного события

Все стандартные события имеют соответствующие защищенные динамические методы, унаследованные от TControl, имена которых образованы от названия события без частицы "On". Например, события OnClick вызывают метод Click.

Как правило, вы сначала обращаетесь к наследованному методу, разрешая пользовательскому обработчику события произвести свои действия перед тем, как сработает код вашего переопределения. Предположим, вы пишете новую компоненту, в которой хотите модифицировать реакцию на щелчки мышью. Вместо того, чтобы присвоить соответствующий обработчик события OnClick, как это сделал бы прикладной программист, вы переопределяете защищенный метод Click (Листинг 6.10).

void _fastcall TMyControl::Click() {

// Стандартное обслуживание, включающая вызов обработчика

TWinControl::Click() ;

// Далее следует ваш код переопределения метода

}

Листинг 6.10. Переопределение защищенного метода.

6.4.2.4 Собственные события

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

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

Определение события проходит через четыре этапа, для реализации которых вам необходимо:

1. Знать, какое действие вызывает событие. Для некоторых событий ответ очевиден. Например, при нажатии левой кнопки мыши Windows посылает сообщение WM_LBUTTONDOWN. Принимая это сообщение, компонента вызывает метод MouseDown, который в свою очередь обращается к обработчику события, который пользователь подсоединил к событию OnMouseDown. Некоторые события менее очевидно связаны с внешними воздействиями. Так линейка прокрутки имеет событие OnChange, которое возникает по разным причинам - в результате щелчков мышью, нажатия управляющих клавиш или изменений в других родственных компонентах.

2. Определить тип обработчика события. Обработчик события может просто опознавать событие нотификации (объектного типа TNotifyEvent) или содержать обработку событий специфического типа. TNotifyEvent задает единственный аргумент - указатель объекта, благодаря которому обработчик "узнает" компоненту, сгенерировавшую это событие. Например, щелчки мышью генерируют события нотификации. Обработчик этих событий знает только то, на какой компоненте пользователь щелкнул мышью. Передача дополнительных адресных аргументов используется, например, обработчиком события типа TKeyPressEvent, вызываемого при нажатии любой клавиши на клавиатуре.

3. Объявить тип и свойство для события. Инспектор объектов определяет, что данное свойство является событием, обнаруживая тип свойства closure, и представляет его на вкладке События. Давайте событиям значимые и описательные имена, по которым пользователь догадается о том, что это за событие. C++Builder рекомендует начинать имена событий с частицы "On.".

4. Создать виртуальный метод, который вызывает обработчик события пользователя и обеспечивает обработку по умолчанию. Правильное функционирование вашей компоненты не должно зависеть от конкретной реакции, которую пользователь заложил в обработчик события. В частности, пустой обработчик события так же допустим, как и его отсутствие. Более того, пользователь имеет право переопределить обработку по умолчанию. Чтобы предоставить ему такую возможность, передайте в обработчик дополнительный адресный аргумент, значение которого можно проверять при возврате. При этом пустой обработчик события не изменит значения аргумента, и обработка по умолчанию всегда будет иметь место после возврата из пустого обработчика.

6.4.2.5 События и сообщения Windows

Опытный программист определенно заметит сходство некоторых событий C++Builder и сообщений Windows. В следующей таблице приведен краткий список событий объекта TForm и соответствующих сообщений Windows, которые вы использовали бы в обычной программе на языке С:Событие VCL Сообщение Windows

OnCreate WM CREATE

OnClose WM DESTROY

OnReSize WM SIZE

OnActivate, OnDeactivate WMACTIVATE

OnShow, OnHide WM SHOWWINDOW

OnKeyDown WM KEYDOWN

OnKeyUp WM KEYUP

OnKeyDown WM KEYDOWN

OnMouseDown WM LBUTTONDOWN, WM RBUTTONDOWN

On Mouse Up WM LBUTTONUP,WM RBUTTONUP

OnMouseMove WMMOUSEMOVE

OnDblClkk WM LBUTTONDBLCLK, WMRBUTTONDBLCLK

OnPaint WM PAINT

He всякому сообщению Windows можно найти соответствующее событие VCL. Например, в обычной программе на языке С для Windows сообщение WM_COMMAND используется как для обслуживания нажатий на кнопки, так и выбора команд из меню. В C++Builder для этих целей используются разные события: TButton::OnClick и TMenuItem::OnCUck, соответственно.

С другой стороны, некоторые события VCL расширяют функциональность встроенных сообщений Windows. Так события OnDragOver и OnDragDrop Объекта TForm просто и прямолинейно реализуют операции перетаскивания (drag-and-drop) в вашей программе. Большинство компонент на вкладках Standard и Win95 Палитры компонент лишь специальным образом обрамляют известные элементы управления Windows. Компоненты на других вкладках представляют совершенно новые элементы управления (и события) для особых областей функционирования.

Компоненты вкладок Standard и Win95 инкапсулируют стандартные элементы управления Windows. За взаимодействие между пользователем и программой, которое ранее поддерживалось реакцией на сообщения Windows, теперь отвечают обработчики событий компонент VCL. Однако, в некоторых ситуациях возникает необходимость "взять на себя" те сообщения Windows, которые не имеют соответствующих событий VCL или не адекватны им. Для таких случаев в VCL предусмотрена методика ООП, обеспечивающая непосредственный отклик на события Windows, подобно средствам библиотек базовых классов OWL или MFC. Эта методика, реализуемая с помощью макросов BEGIN_MESSAGE_MAP, MESSAGE.HANDLER и END_MESSAGE_MAP, весьма трудоемка и здесь не рассматривается. Поэтому предварительно тщательно просмотрите имеющиеся в VCL компоненты, которые могут содержать подходящие события.