О чём не пишут в книгах по 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
).
Поделиться:
Популярные книги
На границе тучи ходят хмуро...
1. Александр Агренев
Фантастика:
альтернативная история
9.28
рейтинг книги
Кодекс Охотника. Книга III
3. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
7.00
рейтинг книги
Последний попаданец 11. Финал. Часть 1
11. Последний попаданец
Фантастика:
фэнтези
юмористическое фэнтези
рпг
5.00
рейтинг книги
Книга пяти колец
1. Книга пяти колец
Фантастика:
фэнтези
6.00
рейтинг книги
Поступь Империи
7. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Купидон с топором
Любовные романы:
современные любовные романы
7.67
рейтинг книги
Наследник в Зеркальной Маске
8. Десять Принцев Российской Империи
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Совок 5
5. Совок
Фантастика:
детективная фантастика
попаданцы
альтернативная история
6.20
рейтинг книги
Аномальный наследник. Том 1 и Том 2
1. Аномальный наследник
Фантастика:
боевая фантастика
альтернативная история
8.50
рейтинг книги
Теневой путь. Шаг в тень
1. Теневой путь
Фантастика:
фэнтези
6.71
рейтинг книги
Попаданка в академии драконов 2
2. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
6.95
рейтинг книги
Гром над Империей. Часть 2
6. Гром над миром
Фантастика:
фэнтези
попаданцы
5.25
рейтинг книги
Ритуал для призыва профессора
Любовные романы:
любовно-фантастические романы
7.00
рейтинг книги
Измена. Осколки чувств
2. Измены
Любовные романы:
современные любовные романы
5.00