- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания О чём не пишут в книгах по Delphi - А. Григорьев
Шрифт:
Интервал:
Закладка:
При обработке сообщений VCL решает две задачи: выборка сообщений из очереди и передача сообщения конкретному компоненту. Рассмотрим сначала первую задачу.
Выборкой сообщений из очереди занимается объект Application, непосредственно за извлечение и диспетчеризацию сообщения отвечает его метод ProcessMessage (листинг 1.13).
Листинг 1.13. Метод TApplication.ProcessMessage
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
Unicode: Boolean;
Handled: Boolean;
MsgExists: Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
begin
Unicode := (Msg.hwnd <> 0) and IsWindowUnicode(Msg.hwnd);
if Unicode then MsgExists := PeekMessageW(Msg, 0, 0, 0, PM_REMOVE)
else MsgExists := PeekMessage(Msg, 0, 0, 0, PM_REMOVE);
if not MsgExists then Exit;
Result := True;
if Msg.Message <> WM_QUIT then
begin
Handled := False;
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
if not IsPreProcessMessage(Msg) and not IsHintMsg(Msg) and not Handled and
not IsMDIMsg(Msg) and not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
begin
TranslateMessage(Msg);
if Unicode then DispatchMessageW(Msg);
else DispatchMessage(Msg);
end;
end else FTerminate := True;
end;
end;
В этом коде отдельного комментария требует то, как используется функция PeekMessage. Сначала эта функция вызывается с параметром PM_NOREMOVE, — так выполняется проверка условия, что в очереди присутствует сообщение, а также выясняется, для какого окна предназначено первое сообщение в очереди. Само сообщение при этом остается в очереди. С помощью функции IsWindowUnicode производится проверка, использует ли окно-адресат кодировку ANSI или Unicode, и затем, в зависимости от этого, сообщение извлекается либо функцией PeekMessage, либо ее Unicode-аналогом PeekMessageW (о Unicode-аналогах функций см. разд. 1.1.12). При диспетчеризации сообщения также вызывается либо функция DispatchMessage, либо ее Unicode-аналог DispatchMessageW.
Если метод ProcessMessage с помощью PeekMessage извлекает из очереди сообщение WM_QUIT, то он устанавливает в True поле FTerminate и завершает свою работу. Обработка всех остальных сообщений, извлеченных из очереди состоит из следующих основных этапов (см. рис. 1.6):
1. Если назначен обработчик Application.OnMessage, сообщение передается ему. В этом обработчике можно установить параметр-переменную Handle в True, что означает, что сообщение не нуждается в дополнительной обработке.
2. Второй шаг —это предварительная обработка сообщения (вызов метода IsPreProcessMessage). Этот шаг появился только начиная с BDS 2006, в более ранних версиях его не было. Обычно предварительную обработку осуществляет то окно, которому предназначено это сообщение, но если окно-адресат не является VCL-окном, производится поиск VCL-окна по цепочке родителей. Кроме того, если какое-либо окно захватит ввод мыши, предварительную обработку сообщений будет осуществлять именно оно. Если оконный компонент, удовлетворяющий этим требованиям, найден, вызывается его метод PreProcessMessage, который возвращает результат логического типа. Если компонент вернул True, то на этом обработка сообщения заканчивается. Отметим, что ни один из стандартных компонентов VCL не использует эту возможность перехвата сообщений, она реализована для сторонних компонентов.
3. Затем, если на экране присутствует всплывающая подсказка (hint), проверяется, должно ли пришедшее сообщение прятать эту подсказку, и если да, то она убирается с экрана (метод IsHintMessage). Список сообщений, которые должны прятать окно подсказки, зависит от класса этого окна (здесь имеется в виду класс VCL, а не оконный класс) и определяется виртуальным методом THintWindow.IsHintMsg. Стандартная реализации этого метода рассматривает как "прячущие" все сообщения от мыши, клавиатуры, сообщения об активации и деактивации программы и о действиях пользователя с меню или визуальными компонентами. Если метод IsHintMessage возвращает False, то сообщение дальше не обрабатывается, но стандартная реализация этого метода всегда возвращает True.
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. Если нажатая клавиша не является "горячей", но относится к клавишам, использующимся для управления диалоговыми окнами (<Tab>, стрелки, <Esc> и т.п.), форме передается сообщение об этом, и при необходимости сообщение обрабатывается. Таким образом, на данном этапе средствами 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).