- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
О чём не пишут в книгах по Delphi - А. Григорьев
Шрифт:
Интервал:
Закладка:
Рассмотрим все методы, с помощью которых можно встроить свой код в цепочку обработки сообщений оконным компонентом и перехватить сообщения. Всего существует шесть способов сделать это.
1. Как и у всякого окна, у оконного компонента VCL можно изменить оконную процедуру с помощью функции SetWindowLong. Этот способ лучше не применять, поскольку код VCL не будет ничего "знать" об этом переопределении, и сообщения, получаемые компонентом не через оконную процедуру, а с помощью Perform, не будут перехвачены. Другой недостаток данного способа — то, что изменение некоторых свойств компонента (например, FormStyle и BorderStyle у формы) невозможно без уничтожения окна и создания нового. Для программиста это пересоздание окна выглядит прозрачно, но новое окно получит новую оконную процедуру, и нужно будет выполнять перехват заново. Отследить момент пересоздания окна можно с помощью сообщения CM_RECREATEWND, обработчик которого уничтожает старое окно, а создание нового окна откладывается до момента первого обращения к свойству Handle. Если перехватить по сообщение, то, в принципе, после выполнения стандартного обработчика можно зaново установить перехват с помощью SetWindowLong, но т.к. этот способ не дает никаких преимуществ перед другими, более простыми, им все равно лучше не пользоваться.
2. Можно создать собственный метод обработки сообщения и поместить указатель на него в свойство WindowProc. При этом старый указатель обычно запоминается, т.к. новый обработчик обрабатывает лишь некоторые сообщения, а остальные передает старому. Достоинство этого способа — то, что метод, указатель на который помещается в WindowProc, не обязан принадлежать тому компоненту, сообщения которого перехватываются. Это позволяет, во-первых, создавать компоненты, которые влияют на обработку сообщений родительскими формами, а во-вторых, реализовывать нестандартную обработку сообщений стандартными компонентами, не порождая от них наследника.
3. При написании нового компонента можно перекрыть виртуальный метод WndProc и реализовать обработку нужных сообщений в нем. Это позволяет компоненту перехватывать сообщения в самом начале цепочки (за исключением внешних обработчиков, установленных с помощью свойства WindowProc — здесь разработчик компонента не властен).
4. Наиболее удобный способ самостоятельной обработки событий — написание их методов-обработчиков. Этот способ встречается чаще всего. Его недостатком является то, что номера обрабатываемых сообщений должны быть известны на этапе компиляции. Для системных сообщений и внутренних сообщений VCL это условие выполняется, но далее мы будем говорить об определяемых пользователем сообщениях, номера которых в некоторых случаях на этапе компиляции неизвестны. Обрабатывать такие сообщения с помощью методов с директивой невозможно.
5. Для перехвата сообщений, которые не были обработаны с помощью методов-обработчиков, можно перекрыть виртуальный метод.
6. И наконец, можно написать оконную процедуру и поместить указатель на нее в свойство DefWndProc. Этот способ по своим возможностям практически эквивалентен предыдущему, но менее удобен. Однако предыдущий способ пригоден только для создания собственного компонента, в то время как DefWndProc можно изменять у экземпляров существующих классов. Напомним, что этот способ не подходит для форм, у которых FormStyle = fsMDIForm, т.к. такие формы игнорируют значение свойства DefWndProc.
Для перехвата сообщений неоконных визуальных компонентов допустимы все перечисленные способы, за исключением первого и последнего.
Метод WndProc оконного компонента транслирует сообщения от мыши неоконным визуальным компонентам, родителем которых он является. Например. если положить на форму компонент TImage и переопределить у этой формы метод для обработки сообщения WM_LBUTTONDOWN, то нажатие кнопки мыши над TImage не приведет к вызову этого метода, т.к. WndProc передаст это сообщение в TImage, и Dispatch не будет вызван. Но если переопределить WndProc или изменить значение свойства WindowProc (т.е. использовать второй или третий метод перехвата), то можно получать и обрабатывать и те "мышиные" сообщения, которые должны транслироваться неоконным дочерним компонентам. Это общее правило: чем раньше встраивается собственный код в цепочку обработки сообщений, тем больше у него возможностей. Как мы уже говорили, начиная с BDS 2006 появился еще один способ перехвата сообщений — перекрытие метода PreProcessMessage. Этот способ нельзя ставить в один ряд с перечисленными ранее шестью способами, т.к. он имеет два существенных отличия от них. Во-первых, с помощью этого способа перехватываются все сообщения, попавшие в петлю сообщений, а не только те, которые посланы конкретному компоненту, из-за чего может понадобиться дополнительная фильтрация сообщений. Во-вторых, метод PreProcessMessage перехватывает сообщения, попавшие в петлю сообщений, а не в оконную процедуру компонента. С одной стороны, это даёт возможность перехватывать те сообщения, которые метод Аррlication.ProcessMessage не считает нужным передавать в оконную процедуру, но с другой стороны, не позволяет перехватывать те сообщения, которые окно получает, минуя петлю сообщений (например, те, которые отправлены с помощью SendMessage или Perform). По этим причинам область применения данного способа совсем другая, чем у способов, связанных с внедрением кода в оконную процедур. Перекрытие PreProcessMessage сопоставимо, скорее, с использованием события Application.OnMessage.
Различные способы перехвата сообщений иллюстрируются рядом примеров на прилагающемся к книге компакт-диске: использование свойства WindowProc показано в примерах Line, CoordLabel и PanelMsg, перекрытие метода WndProc — в примере NumBroadcast, создание метода для обработки сообщения — в примере ButtonDel.
1.1.9. Сообщения, определяемые пользователем
Сообщения очень удобны в тех случаях, когда нужно заставить окно выполнить какое-то действие. Поэтому Windows предоставляет возможность программисту создавать свои сообщения. Существуют три типа пользовательских сообщений:
□ сообщения оконного класса;
□ сообщения приложения;
□ глобальные (строковые) сообщения.
Для каждого из них выделен отдельный диапазон номеров. Номера стандартных сообщений лежат в диапазоне от 0 до WM_USER-1 (WM_USER — константа, для 32-разрядных версий Windows равная 1024).
Сообщения оконного класса имеют номера в диапазоне от WM_USER до WM_APP-1 (WM_APP имеет значение 32 768). Программист может выбирать произвольные номера для своих сообщений в этом диапазоне. Каждое сообщение должно иметь смысл только для конкретного оконного класса. Для различных оконных классов можно определять сообщения, имеющие одинаковые номера. Система никак не следит за тем, чтобы сообщения, определенные для какого-либо оконного класса, посылались только окнам этого класса — программист должен сам об этом заботиться. В этом же диапазоне лежат сообщения, специфические для стандартных оконных классов 'BUTTON', 'EDIT', 'LISTBOX', 'COMBOBOX' и т.п.
Использование сообщений из этого диапазона иллюстрируется примером ButtonDel.
Диапазон от WM_APP до 49 151 (для этого значения константа не предусмотрена) предназначен для сообщений приложения. Номера этих сообщений также выбираются программистом произвольно. Система гарантирует, что ни один из стандартных оконных классов не задействует сообщения из этого диапазона. Это позволяет выполнять их широковещательную в пределах приложения рассылку. Ни один из стандартных классов не откликнется на такое сообщение и не выполнит нежелательных действий.
Упоминавшиеся ранее внутренние сообщения VCL с префиксами CM_ и CN_ имеют номера в диапазоне от 45 056 до 49 151, т.е. используют часть диапазона сообщений приложения. Таким образом, при использовании VCL диапазон сообщений приложения сокращается до WM_APP..45055. Сообщения оконного класса и приложения пригодны и для взаимодействия с другими приложениями, но при этом отправитель должен быть уверен, что адресат правильно его поймет. Широковещательная рассылка при этом исключена — реакция других приложений, которые также получат это сообщение, может быть непредсказуемой. Если все же необходимо рассылать широковещательные сообщения между приложениями, то следует воспользоваться глобальными сообщениями, для которых зарезервирован диапазон номеров от 49 152 до 65 535.
Глобальное сообщение обязано иметь имя (именно поэтому такие сообщения называются также строковыми), под которым оно регистрируется в системе с помощью функции в RegisterWindowMessage. Эта функция возвращает уникальный номер регистрируемого сообщения. Если сообщение с таким именем регистрируется впервые, номер выбирается из числа ещё не занятых. Если же сообщение с таким именем уже было зарегистрировано, то возвращается тот же самый номер, который был присвоен ему при первой регистрации. Таким образом, разные программы, регистрирующие сообщения с одинаковыми именами, получат одинаковые номера и смогут понимать друг друга. Для прочих же окон это сообщение не будет иметь никакого смысла. Создание и использование оконных сообщений демонстрируется примером NumBroadcast, содержащимся на прилагаемом компакт-диске. Разумеется, существует вероятность, что два разных приложения выберут для своих глобальных сообщений одинаковые имена, и это приведет к проблемам при широковещательной рассылке этих сообщений. Но, если давать своим сообщениям осмысленные имена, а не что-то вроде WM_MYMESSAGE1, вероятность такого совпадения будет очень мала. В особо критических ситуациях можно в качестве имени сообщения использовать GUID, уникальность которого гарантируется.

