7. Если на экране присутствует один из стандартных диалогов (в VCL они реализуются классами TOpenDialog
, TSaveDialog
и т.п.), то вызывается функция IsDialogMessage
, чтобы эти диалоги могли нормально функционировать (метод IsDlgMsg
).
8. Если ни на одном из предыдущих этапов сообщение не было обработано, то вызываются функции TranslateMessage
и DispatchMessage
, которые завершают обработку сообщения путем направления его соответствующей оконной функции.
Примечание
Если внимательно проанализировать шестой этап обработки сообщения, видно, что нажатая комбинация клавиш проверяется на соответствие "горячим" клавишам меню сначала активной формы, затем — главной. При этом сначала возникает событие OnShortCut
активной формы, потом — Application.OnShortCut
, затем — OnShortCut
главной формы. Если в момент получения сообщения главная форма активна, то она дважды будет проверять соответствие клавиши "горячим" клавишам своих меню и событие OnShortCut
тоже возникнет дважды (первый раз поле Msg.Msg
равно CN_KEYDOWN
, второй — CM_APPKEYDOWN
). Эта проверка осуществляется дважды только в том случае, если комбинация клавиш не распознается как "горячая" клавиша — в противном случае цепочка проверок обрывается при первой проверке.
Метод ProcessMessage
возвращает True
, если сообщение извлечено и обработано, и False
, если очередь была пуста. Этим пользуется метод HandleMessage
, который вызывает ProcessMessage
и, если тот вернет False
, вызывает метод Application.Idle
для низкоприоритетных действий, которые должны выполняться только при отсутствии сообщений в очереди. Метод Idle
, во-первых, проверяет, над каким компонентом находится курсор мыши, и сохраняет ссылку на него в поле FMouseControl
, которое используется при последующей проверке, нужно ли прятать всплывающую подсказку. Затем, при необходимости, прячется старая всплывающая подсказка и показывается новая. После этого вызывается обработчик Application.OnIdle
, если он назначен. Этот обработчик имеет параметр Done
, по умолчанию равный True
. Если в коде обработчика он не меняется на False
, метод Idle
инициирует события OnUpdate
у всех объектов TAction
, у которых они назначены (если Done
после вызова принял значение False
, HandleMessage
не тратит время на инициацию событий OnUpdate
).
Примечание
В BDS 2006 появилось свойство Application.ActionUpdateDelay
, позволяющее снизить нагрузку на процессор, откладывая на некоторое время обновление объектов TAction
. Если значение этого свойства не равно нулю, в методе Idle
вместо вызова запускается таймер и OnUpdate
вызывается по его сигналу.
Затем, независимо от значения Done
, с помощью процедуры CheckSynchronize
проверяется, есть ли записи в списке методов, ожидающих синхронизации (эти методы помещаются в указанный список при вызове TThread.Synchronize
). Если список не пуст, выполняется первый из этих методов (при этом он, разумеется, удаляется из списка). Затем, если остался равным True
, а список методов для синхронизации был пуст (т. е. никаких дополнительных действий выполнять не нужно), HandleMessage
вызывает функцию Windows API WaitMessage
. Эта функция приостанавливает выполнение нити до тех пор, пока в ее очереди не появятся сообщения.
Примечание
Вызов Synchronize
приводит к тому, что соответствующий метод будет выполнен основной нитью приложения, а нить, вызвавшая Synchronize
, будет приостановлена до тех пор, пока главная нить не сделает это. Отсюда видно, насколько бредовыми являются советы (заполонившие Интернет, а также встречающиеся в некоторых книгах, например, у Архангельского) помещать весь код нити в Synchronize
. В этом случае дополнительная нить вообще не будет ничего делать, все будет выполняться основной нитью, и выигрыша от создания дополнительной нити просто не будет. Поэтому в Synchronize
нужно помещать только те действия, которые не могут быть выполнены неосновной нитью (например, обращения к свойствам и методам VCL-компонентов).
Главная петля сообщений в VCL реализуется методом Application.Run
, вызов которого автоматически вставляется в dpr-файл VCL-проекта. Application.Run
вызывает в цикле метод HandleMessage
, пока поле FTerminate
не окажется равным True
(напомним, что значение True
присваивается этому полю, когда ProcessMessage
извлекает из очереди сообщение WM_QUIT
, а также при обработке сообщения WM_ENDSESSION
и при закрытии главной формы).
Читать дальше
Конец ознакомительного отрывка
Купить книгу