Параметр метода для обработки сообщения имеет тип, соответствующий обрабатываемому сообщению (при необходимости можно описать свой тип), или тип TMessage
. Таким образом, обработчик сообщения WM_MOUSEMOVE
будет выглядеть так, как показано в листинге 1.16.
Листинг 1.16. Объявление и реализация метода для обработки сообщения WM_MOUSEMOVE
type
TSomeForm = class(TForm)
...............
procedure WMNCMouseMove(var Message: TWMNCMouseMove); message WM_NCMOUSEMOVE;
................
end;
procedure TSomeForm.WMNCMouseMove(var Message: TWMNCMouseMove);
begin
...............
inherited; // Возможно, этот вызов не будет нужен
end;
Метод для обработки сообщения может выполнить ее полностью самостоятельно, тогда он не должен вызывать унаследованный метод обработки сообщения. Если же реакция предка на сообщение в целом устраивает разработчика, но нуждается только в дополнении, ключевое слово inherited
позволяет вызвать унаследованный обработчик для данного сообщения. Таким образом, может образовываться целая цепочка вызовов унаследованных обработчиков одного и того же сообщения, каждый из которых выполняет свою часть обработки. Если у предков класса нет обработчика данного сообщения, директива inherited
передает управление методу TObject.DetaultHandler
. Вернемся к методу Dispatch
. Он ищет среди обработчиков сообщения класса (собственных или унаследованных) метод для обработки сообщения, заданного полем Msg
параметра Message
и, если находит, передает управление ему. Если ни сам класс, ни его предки не содержат обработчика данного сообщения, то обработка передаётся методу DefaultHandler
.
Метод DefaultHandler
виртуальный, в классе TObject
он не выполняет никаких действий, но наследники его переопределяют. Впервые он переопределяется в классе TControl
для обработки сообщений, связанных с получением и установкой заголовка окна — WM_GETTEXT
, WM_GETTEXTLENGTH
и WM_SETTEXT
. Напомним, что класс TControl является предком для всех визуальных компонентов, а не только оконных, и появление обработчика системных сообщений в этом классе — часть той имитации обработки сообщений неоконными компонентами, о которой мы уже говорили.
В классе TWinControl
метод DefaultHandler
также переопределен. Помимо передачи некоторых сообщений дочерним окнам (об этом мы будем подробнее говорить чуть позже) и обработки некоторых внутренних сообщений он вызывает оконную процедуру, адрес которой хранится в свойстве DefWndProc
. Это свойство содержит адрес, который был присвоен полю WindowClass.lpfnWndProc
структуры TCreateParams
в методе CreateParams
. По умолчанию это поле содержит адрес стандартной оконной процедуры DefWindowProc
. Как было сказано ранее, обработка сообщений при использовании API обычно завершается вызовом этой процедуры. В классе TCustomForm
метод DefaultHandler
также переопределен, если форма является MDI-формой, сообщения, присланные ей, передаются в процедуру DefFrameProc
(за исключением WM_SIZE
, которое передается в DefWindowProc
) независимо от того, какое значение имеет свойство DefWindowProc
. Для всех остальных типов форм вызывается унаследованный от TWinControl DefaultHandler
.
Повторим еще раз всю цепочку обработки сообщений оконными компонентами VCL (рис. 1.7). Для каждого компонента создается уникальная оконная процедура, которая передает управление методу MainWndProc
. MainWndProc
передает управление методу, указатель на который хранится в свойстве WindowProc
. По умолчанию это метод компонента WndProc
. Он осуществляет обработку некоторых сообщений, но в большинстве случаев передает управление методу Dispatch
, который ищет среди методов компонента или его предков обработчик данного сообщения. Если обработчик не найден, управление получает метод DefaultHandler
(он может также получить управление и в том случае, если обработчик найден, но он вызывает inherited
). DefaultHandler
самостоятельно обрабатывает некоторые сообщения, но большинство из них передаётся оконной процедуре, адрес хранится в свойстве DefWndProc
(по умолчанию это стандартная функция Windows API DefWindowProc
).
Рис. 1.7.Блок-схема оконной процедуры оконных компонентов VCL
Класс TControl
имеет метод Perform
, с помощи которого можно заставить визуальный компонент выполнить обработку конкретного сообщения в обход оконной процедуры и системного механизма передачи сообщений. Perform
приводит к непосредственному вызову метода, указатель на который хранится в свойстве WindowProc
. Дальше цепочка обработки сообщений такая же, как и при получении сообщения через оконную процедуру. Для оконных компонентов вызов Perform
по своим последствиям практически эквивалентен передаче сообщения с помощью SendMessage
с двумя исключениями. Во-первых, при использовании SendMessage
система обеспечивает переключение между нитями, и сообщение будет выполнено в той нити, которая создала окно, a Perform
никакого переключения не производит, и обработка сообщения будет выполнена той нитью, которая вызвала Perform
. Поэтому Perform
, в отличие от SendMessage
, можно использовать только в главной нити (напомним, что VCL — принципиально однонитевая библиотека, и создание форм вне главной нити с ее помощью недопустимо). Во-вторых, Perform
выполняется чуть быстрее, т.к. оконная процедура и метод MainWndProc
исключаются из цепочки обработки сообщения.
Читать дальше
Конец ознакомительного отрывка
Купить книгу