TN062. Отражение сообщений для элементов управления окнами
Примечание.
Следующее техническое примечание не было обновлено, поскольку сначала оно было включено в электронную документацию. В результате некоторые процедуры и разделы могут быть устаревшими или неверными. Для получения последних сведений рекомендуется выполнить поиск интересующей темы в алфавитном указателе документации в Интернете.
Эта техническая заметка описывает отражение сообщений, новую функцию в MFC 4.0. Он также содержит инструкции по созданию простого многократного элемента управления, использующего отражение сообщений.
Эта техническая заметка не обсуждает отражение сообщений, так как оно применяется к элементам ActiveX (ранее называемым элементами управления OLE). См. статью ActiveX Controls: подкласс элемента управления Windows.
Что такое сообщение Рефлексия
Элементы управления Windows часто отправляют сообщения уведомлений в родительские окна. Например, многие элементы управления отправляют уведомление о цвете элемента управления (WM_CTLCOLOR или один из его вариантов), чтобы разрешить родительскому элементу предоставить кисть для рисования фона элемента управления.
В Windows и MFC до версии 4.0 родительский окно, часто диалоговое окно, отвечает за обработку этих сообщений. Это означает, что код для обработки сообщения должен находиться в классе родительского окна и должен дублироваться в каждом классе, который должен обрабатывать это сообщение. В приведенном выше случае каждое диалоговое окно, которое хотело управлять пользовательскими фонами, потребуется обработать сообщение о цвете элемента управления. Было бы гораздо проще повторно использовать код, если класс элемента управления может быть написан, который будет обрабатывать свой собственный цвет фона.
В MFC 4.0 старый механизм по-прежнему работает— родительские окна могут обрабатывать сообщения уведомлений. Кроме того, MFC 4.0 упрощает повторное использование, предоставляя функцию "отражение сообщений", которая позволяет обрабатывать эти сообщения уведомлений в окне дочернего элемента управления или родительском окне или в обоих. В примере цвета фона элемента управления теперь можно написать класс элемента управления, который задает свой собственный цвет фона, обрабатывая отраженное WM_CTLCOLOR сообщение — все без использования родительского элемента. (Обратите внимание, что так как отражение сообщений реализуется MFC, а не Windows, родительский класс окна должен быть производным от CWnd
отражения сообщений для работы.)
Старые версии MFC сделали что-то похожее на отражение сообщений, предоставляя виртуальные функции для нескольких сообщений, таких как сообщения для полей списка нарисованных владельцем (WM_DRAWITEM и т. д.). Новый механизм отражения сообщений обобщен и согласован.
Отражение сообщений обратно совместимо с кодом, написанным для версий MFC до 4.0.
Если вы предоставили обработчик для определенного сообщения или для диапазона сообщений в классе родительского окна, он переопределит отражающие обработчики сообщений для того же сообщения, если вы не вызываете функцию обработчика базового класса в собственном обработчике. Например, если вы обрабатываете WM_CTLCOLOR в классе диалогового окна, обработка переопределит любые отражаемые обработчики сообщений.
Если в родительском классе окна вы предоставляете обработчик для определенного сообщения WM_NOTIFY или диапазона сообщений WM_NOTIFY, обработчик будет вызываться только в том случае, если дочерний элемент управления, отправляющий эти сообщения, не имеет отражающего обработчика сообщений ON_NOTIFY_REFLECT()
. Если вы используете ON_NOTIFY_REFLECT_EX()
в карте сообщений, обработчик сообщений может или не позволить родительскому окну обрабатывать сообщение. Если обработчик возвращает ЗНАЧЕНИЕ FALSE, сообщение будет обрабатываться родительским, а вызов , возвращающий ЗНАЧЕНИЕ TRUE , не позволяет родительскому объекту обрабатывать его. Обратите внимание, что отраженное сообщение обрабатывается перед сообщением уведомления.
При отправке сообщения WM_NOTIFY элемент управления предоставляется первый шанс обработать его. Если отправляется любое другое отражаемое сообщение, родительское окно имеет первый шанс обработать его, а элемент управления получит отражаемое сообщение. Для этого потребуется функция обработчика и соответствующая запись в карте сообщений класса элемента управления.
Макрос карты сообщений для отраженных сообщений немного отличается от обычных уведомлений: он _REFLECT добавлен к обычному имени. Например, для обработки сообщения WM_NOTIFY в родительском элементе используется макрос ON_NOTIFY на карте сообщений родительского объекта. Чтобы обработать отраженное сообщение в дочернем элементе управления, используйте макрос ON_NOTIFY_REFLECT в карте сообщений дочернего элемента управления. В некоторых случаях параметры также отличаются. Обратите внимание, что ClassWizard обычно может добавлять записи карты сообщений для вас и предоставлять реализации функций скелета с правильными параметрами.
Сведения о новом сообщении WM_NOTIFY см. в разделе TN061: ON_NOTIFY и сообщения WM_NOTIFY .
Прототипы записей и функций обработчика сообщений для Рефлексия сообщений
Чтобы обработать отражаемое сообщение об уведомлении элемента управления, используйте макросы карты сообщений и прототипы функций, перечисленные в таблице ниже.
КлассWizard обычно может добавлять эти записи карты сообщений для вас и предоставлять реализации функций скелета. Сведения об определении обработчика сообщений для Рефлексия Рефлексия сообщения см. в разделе "Определение обработчиков для отраженных сообщений".
Чтобы преобразовать имя сообщения в отражаемое имя макроса, добавьте ON_ и добавьте _REFLECT. Например, WM_CTLCOLOR становится ON_WM_CTLCOLOR_REFLECT. (Чтобы узнать, какие сообщения могут быть отражены, выполните противоположное преобразование записей макроса в таблице ниже.)
Ниже приведены три исключения из приведенного выше правила.
Макрос для уведомлений WM_COMMAND ON_CONTROL_REFLECT.
Макрос для отражения WM_NOTIFY ON_NOTIFY_REFLECT.
Макрос для отражения ON_UPDATE_COMMAND_UI ON_UPDATE_COMMAND_UI_REFLECT.
В каждом из указанных выше особых случаев необходимо указать имя функции-члена обработчика. В других случаях необходимо использовать стандартное имя для функции обработчика.
Значения параметров и возвращаемых значений функций документируются под именем функции или именем функции с предварительно заданным значением. Например, CtlColor
документируется в OnCtlColor
. Для нескольких отражаемых обработчиков сообщений требуется меньше параметров, чем аналогичные обработчики в родительском окне. Просто совпадайте с именами в таблице ниже с именами формальных параметров в документации.
Запись карты | Прототип функции |
---|---|
ON_CONTROL_REFLECT(,memberFxn wNotifyCode ) |
afx_msg voidmemberFxn ( ); |
ON_NOTIFY_REFLECT(,memberFxn wNotifyCode ) |
afx_msg voidmemberFxn (результат NMHDRpNotifyStruct *, LRESULT);* |
ON_UPDATE_COMMAND_UI_REFLECT(memberFxn ) |
afx_msg voidmemberFxn (CCmdUI);*pCmdUI |
ON_WM_CTLCOLOR_REFLECT( ) | afx_msg HBRUSH CtlColor (CDCpDC *, UINT);nCtlColor |
ON_WM_DRAWITEM_REFLECT( ) | afx_msg void DrawItem (LPDRAWITEMSTRUCTlpDrawItemStruct ); |
ON_WM_MEASUREITEM_REFLECT( ) | afx_msg void MeasureItem (LPMEASUREITEMSTRUCTlpMeasureItemStruct ); |
ON_WM_DELETEITEM_REFLECT( ) | afx_msg void DeleteItem (LPDELETEITEMSTRUCTlpDeleteItemStruct ); |
ON_WM_COMPAREITEM_REFLECT( ) | afx_msg int CompareItem (LPCOMPAREITEMSTRUCTlpCompareItemStruct ); |
ON_WM_CHARTOITEM_REFLECT( ) | afx_msg int CharToItem (UINTnKey , UINT);nIndex |
ON_WM_VKEYTOITEM_REFLECT( ) | afx_msg int VKeyToItem (UINTnKey , UINT);nIndex |
ON_WM_HSCROLL_REFLECT( ) | afx_msg void HScroll (UINTnSBCode , UINT);nPos |
ON_WM_VSCROLL_REFLECT( ) | afx_msg void VScroll (UINTnSBCode , UINT);nPos |
ON_WM_PARENTNOTIFY_REFLECT( ) | afx_msg void ParentNotify (UINTmessage , LPARAM);lParam |
Макросы ON_NOTIFY_REFLECT и ON_CONTROL_REFLECT имеют различные варианты, позволяющие обрабатывать несколько объектов (например, элемент управления и его родительский элемент).
Запись карты | Прототип функции |
---|---|
ON_NOTIFY_REFLECT_EX(,memberFxn wNotifyCode ) |
afx_msg BOOLmemberFxn (NMHDRpNotifyStruct *, LRESULT);* |
ON_CONTROL_REFLECT_EX(,memberFxn wNotifyCode ) |
afx_msg BOOLmemberFxn ( ); |
Обработка Рефлексия сообщений: пример повторного использования элемента управления
В этом простом примере создается многократно используемый элемент управления CYellowEdit
. Элемент управления работает так же, как обычный элемент управления редактирования, за исключением того, что он отображает черный текст на желтом фоне. Было бы легко добавить функции-члены, позволяющие CYellowEdit
элементу управления отображать различные цвета.
Пример создания повторно используемых элементов управления
Создайте диалоговое окно в существующем приложении. Дополнительные сведения см. в разделе редактора диалогов .
У вас должно быть приложение, в котором необходимо разработать повторно используемый элемент управления. Если у вас нет существующего приложения, создайте диалоговое приложение с помощью AppWizard.
С помощью проекта, загруженного в Visual C++, используйте ClassWizard для создания нового класса, вызываемого
CYellowEdit
наCEdit
основе.Добавьте в класс три переменные-члены
CYellowEdit
. Первые два будут переменными COLORREF для хранения цвета текста и цвета фона. ТретийCBrush
будет объектом, который будет держать кисть для рисования фона. ОбъектCBrush
позволяет создать кисть один раз, просто ссылаясь на нее после этого, и автоматически уничтожить кисть приCYellowEdit
уничтожении элемента управления.Инициализировать переменные-члены, написав конструктор следующим образом:
CYellowEdit::CYellowEdit() { m_clrText = RGB(0, 0, 0); m_clrBkgnd = RGB(255, 255, 0); m_brBkgnd.CreateSolidBrush(m_clrBkgnd); }
С помощью ClassWizard добавьте обработчик для отраженного сообщения WM_CTLCOLOR в
CYellowEdit
класс. Обратите внимание, что знак равенства перед именем сообщения в списке сообщений, который можно обрабатывать, указывает на то, что сообщение отражено. Это описано в разделе "Определение обработчика сообщений" для Рефлексия указанного сообщения.ClassWizard добавляет для вас следующую функцию макроса карты сообщений и скелета:
ON_WM_CTLCOLOR_REFLECT() // Note: other code will be in between.... HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor) { // TODO: Change any attributes of the DC here // TODO: Return a non-NULL brush if the // parent's handler should not be called return NULL; }
Замените текст функции следующим кодом. Код задает цвет текста, цвет фона текста и цвет фона для остальной части элемента управления.
pDC->SetTextColor(m_clrText); // text pDC->SetBkColor(m_clrBkgnd); // text bkgnd return m_brBkgnd; // ctl bkgnd
Создайте элемент управления редактирования в диалоговом окне, а затем подключите его к переменной-члену, дважды щелкнув элемент управления редактированием при удержании ключа элемента управления вниз. В диалоговом окне "Добавление переменной элемента" завершите имя переменной и выберите "Control" для категории, а затем "CYellowEdit" для типа переменной. Не забудьте задать порядок вкладок в диалоговом окне. Кроме того, не забудьте включить файл заголовка элемента
CYellowEdit
управления в файл заголовка диалогового окна.Скомпилируйте и запустите приложение. Элемент управления редактирования будет иметь желтый фон.
См. также
Технические примечания по номеру
Технические примечания по категории