OpenGL в Delphi

Перехват сообщений


Большинство событий формы и компонентов являются аналогами соответствующих сообщений операционной системы.
Конечно, не все сообщения имеют такие аналоги, поскольку их (сообщений) очень много, несколько сотен. С каждой новой версией Delphi y формы появляются все новые и новые свойства и события, благодаря чему программировать становится все удобнее, но зато размеры откомпилированного приложения все растут и растут.

Замечание
В угоду программистам, до сих пор использующим третью версию Delphi для получения сравнительно небольших по объему исполняемых модулей, все примеры данной книги я разрабатывал именно в этой версии, но все они прекрасно компилируются и в более старших версиях

У программистов всегда будет возникать потребность обрабатывать сообщения, не имеющие аналогов в списке событий, либо самостоятельно перехватывать сообщения, для которых есть аналоги среди событий формы и компонентов. Как увидим ниже, сделать это несложно.
Для начала обратимся к проекту из подкаталога Exl3, где мы опять будем программировать без VCL. Задача состоит в том, чтобы при двойном щелчке левой кнопкой мыши выводились текущие координаты указателя. Прежде всего обратите внимание, что в стиль окна добавилась константа cs_Dblclks, чтобы окно могло реагировать на двойной щелчок, а оконная функция дополнилась обработкой сообщения wm_LButtonDblclk, в которой выводятся координаты курсора.
Теперь создадим обработчик этого же сообщения в проекте Delphi обычного типа (проект располагается в подкаталоге Exl4).
Описание класса формы я дополнил разделом protected, в который поместил forward-описание соответствующей процедуры:

procedure MesDblClick (var MyMessage TWMMouse); message
wm LButtonDblClk;

Замечание
Как правило, перехватчики сообщений для повышения надежности работы приложения описываются в блоке protected

Имя процедуры я задал таким, чтобы не появлялось предупреждение компилятора о том, что я перекрываю соответствующее событие формы.
Служебное слово message указывает на то, что процедура будет перехватывать сообщение, мнемонику которого указывают за этим словом. Тип аргумента процедуры-перехватчика индивидуален для каждого сообщения. Имя аргумента произвольно, но, конечно, нельзя брать в качестве имени служебное СЛОВО message.
Пожалуй, самым сложным в процессе описания перехвата сообщений является определение типа аргумента процедуры, здесь оперативная помощь оказывается малополезной. В четвертой и пятой версиях Delphi инспектор кода облегчает задачу, но незначительно.
Чтобы решить эту задачу для сообщения wm_LButtonDblclk, я просмотрел все вхождения фразы "LButtonDblClk" в файле messages. pas и обнаружил строку, подсказавшую решение:

TWMLButtonDblClk = TWMMouse;

В этом же файле я нашел описание структуры Twmouse, чем и воспользовался при кодировании процедуры MesDblclick для получения координат курсора Обратите внимание, что здесь не пришлось самостоятельно разбивать по словам значение параметра, как в предыдущем проекте Итак, в рассматриваемом примере перехватывается сообщение "двойной щелчок левой кнопки мыши". Событие Dblclick формы наступает точно в такой же ситуации. Выясним, какая из двух процедур, перехватчик сообщения или обработчик события, имеет преимущество или же они равноправны. Создайте обработчик события OnDblclick формы - вывод любого тестового сообщения (можете воспользоваться готовым проектом из подкаталога Exl5). Запустите проект, дважды щелкните на форме. Процедура-перехватчик среагирует первой и единственной, до обработчика события очередь не дойдет.

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

В проекте из подкаталога Exl6 создан обработчик сообщения wmPaint - перерисовка окна:

protected
procedure WMPaint(var Msg: TWMPaint); message WM_PAINT;
...
procedure TForml. WMPaint(var Msg: TWMPaint);
var
ps: TPaintStruct;
begin
BeginPaint(Handle, ps);
Rectangle (Canvas. Handle, 10, 10, 100, 100);
EndPaint(Handle, ps);
end;

Строки Beginpaint и EndPaint присутствуют для более корректной работы приложения, при их удалении появляется неприятное мерцание при изменении размеров окна. Обратите внимание на функцию построения прямоугольника: я воспользовался тем, что свойство canvas. Handle и есть ссылка на контекст устройства, соответствующая окну формы
Точно так же, как перехватчики сообщений предпочтительнее обработчиков событий, использование непосредственно ссылок на окно и ссылок на контекст устройства предпочтительнее использования их аналогов из мира ООП.
Запомните этот пример, таким приемом мы будем пользоваться очень часто



Содержание раздела