О чём не пишут в книгах по Delphi
Шрифт:
procedure <Name>(var Message: <TMsgType>); message <MsgNumber>;
<MsgNumber>
— это номер сообщения, для обработки которого предназначен метод. Имя метода может быть любым, но традиционно оно совпадает с именем константы сообщения за исключением того, что в нем выбран более удобный регистр символов и отсутствует символ "_" (например, метод для обработки WM_SIZE
будет называться WMSize
). В качестве типа параметра
<TMsgType>
компилятор разрешает любой тип, но на практике имеет смысл только использование типа TMessage
или "совместимого" с ним. Тип TMessage
описан в листинге 1.14. Листинг 1.14.
Описание типа
TMessage
TMessage = packed record
Msg: Cardinal;
case Integer of
0: (
WParam: LongInt;
LParam: LongInt;
Result: LongInt);
1: (
WParamLo: Word;
WParamHi: Word;
LParamLo: Word;
LParamHi: Word;
ResultLo: Word;
ResultHi: Word);
end;
Поле Msg содержит номер сообщения, поля
WParam
и LParam
— значение одноименных параметров сообщения. Поле Result
— выходное: метод, осуществляющий окончательную обработку сообщения, заносит в него то значение, которое должна вернуть оконная процедура. Поля с суффиксами Lo
и Hi
позволяют обращаться отдельно к младшему и старшему словам соответствующих полей, что может быть очень полезно, когда эти параметры содержат пару 16-разрядных значений. Например, у сообщения WM_MOUSEREMOVE
младшее слово параметра LParam
содержит X-координату мыши, старшее — Y-координату. В случае обработки этого сообщения поле LParamLo
будет содержать X-координату, LParamHi
— Y-координату. "Совместимыми" с
TMessage
можно назвать структуры, которые имеют такой же размер, а также параметр Msg
, задающий сообщение. Эти структуры учитывают специфику конкретного сообщения. Их имена образуются из имени сообщения путем отбрасывания символа и добавления префикса T
. Для уже упоминавшегося сообщения WM_MOUSEMOVE
соответствующий тип выглядит, как показано в листинге 1.15. Листинг 1.15. Тип
TWMNCMouseMove
TWMNCMouseMove = packed record
Msg: Cardinal;
HitTest: LongInt;
XCursor: SmallInt;
YCursor: SmallInt;
Result: LongInt;
end;
Параметр
WParam
переименован в HitTest
, что лучше отражает его смысл в данном случае, а параметр LParam
разбит на две 16-разрядных части: XCursor
и YCursor
. Параметр метода для обработки сообщения имеет тип, соответствующий обрабатываемому сообщению (при необходимости можно описать свой тип), или тип
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
).
Поделиться:
Популярные книги
Архил...? 4
4. Архил...?
Фантастика:
фэнтези
попаданцы
альтернативная история
5.50
рейтинг книги
Мятежник
4. Стеллар
Фантастика:
боевая фантастика
7.39
рейтинг книги
Дурашка в столичной академии
Фантастика:
фэнтези
7.80
рейтинг книги
Котенок. Книга 3
3. Котенок
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Аристократ из прошлого тысячелетия
3. Соприкосновение миров
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Печать мастера
6. Гибрид
Фантастика:
попаданцы
технофэнтези
аниме
фэнтези
6.00
рейтинг книги
Господин следователь. Книга 3
3. Господин следователь
Детективы:
исторические детективы
5.00
рейтинг книги
Вернуть невесту. Ловушка для попаданки 2
2. Вернуть невесту
Любовные романы:
любовно-фантастические романы
7.88
рейтинг книги
Командир Красной Армии
1. Командир Красной Армии
Фантастика:
попаданцы
8.72
рейтинг книги
Рота Его Величества
Новые герои
Фантастика:
боевая фантастика
8.55
рейтинг книги
Босс Мэн
Любовные романы:
современные любовные романы
8.97
рейтинг книги
Два лика Ирэн
Любовные романы:
любовно-фантастические романы
6.08
рейтинг книги
Не грози Дубровскому! Том III
3. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 27
27. Лекарь
Фантастика:
аниме
фэнтези
5.00