А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
4. Далее проверяется значение параметра Handled
, установленное в обработчике OnMessage
(если он назначен). Если это значение равно True
, метод ProcessMessage
завершает свою работу, и обработка сообщения на этом заканчивается. Таким образом, обработка сообщения по событию OnMessage
не может отменить предварительную обработку сообщения и исчезновение всплывающей подсказки.

Рис. 1.6.Одна итерация петли сообщений VCL (блок-схема метода Application.ProcessMessage
)
5. Если главная форма приложения имеет стиль MDIForm, и одно из его дочерних MDI-окон в данный момент активно, сообщение передается функции TranslateMDISysAccel
. Если эта функция вернет True
, то обработка сообщения на этом завершается (все эти действия выполняются в методе IsMDIMsg
).
6. Затем, если получено клавиатурное сообщение, оно отправляется на предварительную обработку тому же окну, что и в пункте 2 (метод IsKeyMsg
). Предварительная обработка клавиатурного сообщения начинается с попытки найти полученную комбинацию клавиш среди "горячих" клавиш контекстно-зависимого меню и выполнить соответствующую команду. Если контекстно-зависимое меню не распознало сообщение как свою "горячую" клавишу, то вызывается обработчик события OnShortCut
окна, осуществляющего предварительную обработку (если это окно не является формой и не имеет этого события, то вызывается OnShortCut
его родительской формы). Если обработчик OnShortCut
не установил свой параметр
Handled в True, полученная комбинация клавиш ищется среди "горячих" клавиш сначала главного меню, а потом — среди компонентов TActionList
. Если и здесь искомая комбинация не находится, возникает событие Application.OnShortCut
, которое также имеет параметр Handled
, позволяющий указать, что сообщение в дополнительной обработке не нуждается. Если обработчик не установил этот параметр, то сообщение передается главной форме приложения, которое пытается найти нажатую комбинацию среди "горячих" клавиш своего контекстного меню, передает его обработчику OnShortCut
, ищет среди "горячих" клавиш главного меню и компонентов TActionList
. Если нажатая клавиша не является "горячей", но относится к клавишам, использующимся для управления диалоговыми окнами (, стрелки, и т.п.), форме передается сообщение об этом, и при необходимости сообщение обрабатывается. Таким образом, на данном этапе средствами VCL эмулируются функции TranslateAccelerator
и IsDialogMessage
.
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
и при закрытии главной формы).
Интервал:
Закладка: