Выбрать главу

var

 Msg: TMsg;

 ...

while GetMessage(Msg, 0, 0, 0) do

begin

 TranslateMessage(Msg);

 DispatchMessage(Msg);

end;

Блок-схема петли сообщений показана на рис. 1.4.

Рис 1.4. Блок-схема петли сообщений

Функция GetMessage возвращает True до тех пор, пока не будет получено сообщение WM_QUIT, указывающее на необходимость завершения программы. Обычная программа для Windows, выполнив предварительные действия (регистрация класса и создание окна), входит в петлю сообщений, которую выполняет до конца своей работы. Все остальные действия выполняются в оконной процедуре при реакции на соответствующие сообщения.

Примечание

Если нить не имеет петли сообщений, сообщения, которые посылаются нам, не будут обработаны. Это следует учитывать при создании таких компонентов, как, например, TTimer и TClientSocket. Эти компоненты создают невидимые окна для получения сообщений, которые необходимы им для работы. Если нить, создавшая эти объекты, не будет иметь петли сообщений, они будут неработоспособными

Сообщение, извлеченное из очереди, GetMessage помещает в первый параметр-переменную типа TMsg. Последние три параметра служат для фильтрации сообщений, позволяя извлекать из очереди только те сообщения, которые соответствуют определенным критериям. Если эти параметры равны нулю, как это обычно бывает, фильтрация при извлечении сообщений не производится.

Функция TranslateMessage, которая обычно вызывается в петле сообщений, служит для трансляции клавиатурных сообщении (если петля сообщений реализуется только для обработки сообщении невидимым окнам, которые использует, например, COM/DCOM, или по каким-то другим причинам ввод с клавиатуры не обрабатывается или обрабатывается нестандартным образом, вызов TranslateMessage можно опустить). Когда пользователь нажимает какую-либо клавишу на клавиатуре, система посылает окну, находящему в фокусе, сообщение WM_KEYDOWN. Через параметры этого сообщения передаётся виртуальный код нажатой клавиши — двухбайтное число, которое определяется только положением нажатой клавиши на клавиатуре и не зависит от текущей раскладки, состояния клавиш <CapsLock> и т.п. Функция TranslateMessage. обнаружив такое сообщение, добавляет в очередь (причем не в конец, а в начало) сообщение WM_CHAR, в параметрах которого передается код символа, соответствующего нажатой клавише, с учетом раскладки, состояния клавиш <CapsLock>, <Shift> и т. п. Именно функция TranslateMessage по виртуальному коду клавиши определяет код символа. При этом нажатие любой клавиши приводит к генерации WM_KEYDOWN, а вот WM_CHAR генерируется не для всех клавиш, а только для тех, которые соответствуют какому-то символу (например, не генерирует WM_CHAR нажатие таких клавиш, как <Shift> <Ctrl>, <Insert>, функциональных клавиш).

Примечание

У многих компонентов VCL есть события OnKeyDown и OnKeyPress. Первое возникает при получении компонентом сообщения WM_KEYDOWN, второе — сообщения WM_CHAR.

Если очередь сообщений пуста, функция GetMessage ожидает, пока там не появится хотя бы одно сообщение, и только после этого завершает работу. Во время этого ожидания нить не загружает процессор.

Петля сообщений может извлечь и отправить на обработку следующее сообщение только тогда, когда оконная процедура закончила обработку предыдущего. Таким образом, сообщение, обработка которого занимает много времени, блокирует обработку следующих сообщений, и все окна, созданные данной нитью, перестают реагировать на действия пользователя. Именно этим объясняется временное зависание программы, которая в одном из своих обработчиков сообщений делает математические расчеты или выполняет длительный запрос к базе данных: сообщения накапливаются в очереди, но не извлекаются из нее и не обрабатываются. Как только обработка текущего сообщения закончится, все остальные сообщения будут извлечены из очереди и обработаны.

В некоторых случаях избежать временного зависания программы помогает организация локальной петли сообщений. Если обработчик сообщения, для работы которого требуется много времени, содержит цикл, в него можно вставить вызовы функции PeekMessage, которая позволяет проверить, есть ли в очереди сообщения. Если сообщения обнаружены, нужно вызвать DispatchMessage для передачи их требуемому окну. В этом случае сообщения будут извлекаться из очереди и обрабатываться до завершения работы обработчика. Блок-схема программы, содержащей локальную петлю сообщений, показана на рис. 1.5 (для краткости в главной петле сообщений показаны только две самых важных функции: GetMessage и DispatchMessage, хотя и в этом случае главная петля целиком выглядит так же, как на рис. 1.4).