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(,memberFxnwNotifyCode) afx_msg voidmemberFxn( );
ON_NOTIFY_REFLECT(,memberFxnwNotifyCode) 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(,memberFxnwNotifyCode) afx_msg BOOLmemberFxn(NMHDRpNotifyStruct*, LRESULT);*
ON_CONTROL_REFLECT_EX(,memberFxnwNotifyCode) afx_msg BOOLmemberFxn( );

Обработка Рефлексия сообщений: пример повторного использования элемента управления

В этом простом примере создается многократно используемый элемент управления CYellowEdit. Элемент управления работает так же, как обычный элемент управления редактирования, за исключением того, что он отображает черный текст на желтом фоне. Было бы легко добавить функции-члены, позволяющие CYellowEdit элементу управления отображать различные цвета.

Пример создания повторно используемых элементов управления

  1. Создайте диалоговое окно в существующем приложении. Дополнительные сведения см. в разделе редактора диалогов .

    У вас должно быть приложение, в котором необходимо разработать повторно используемый элемент управления. Если у вас нет существующего приложения, создайте диалоговое приложение с помощью AppWizard.

  2. С помощью проекта, загруженного в Visual C++, используйте ClassWizard для создания нового класса, вызываемого CYellowEdit на CEditоснове.

  3. Добавьте в класс три переменные-члены CYellowEdit . Первые два будут переменными COLORREF для хранения цвета текста и цвета фона. Третий CBrush будет объектом, который будет держать кисть для рисования фона. Объект CBrush позволяет создать кисть один раз, просто ссылаясь на нее после этого, и автоматически уничтожить кисть при CYellowEdit уничтожении элемента управления.

  4. Инициализировать переменные-члены, написав конструктор следующим образом:

    CYellowEdit::CYellowEdit()
    {
        m_clrText = RGB(0, 0, 0);
        m_clrBkgnd = RGB(255, 255, 0);
        m_brBkgnd.CreateSolidBrush(m_clrBkgnd);
    }
    
  5. С помощью 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;
    }
    
  6. Замените текст функции следующим кодом. Код задает цвет текста, цвет фона текста и цвет фона для остальной части элемента управления.

    pDC->SetTextColor(m_clrText);   // text
    pDC->SetBkColor(m_clrBkgnd);    // text bkgnd
    return m_brBkgnd;               // ctl bkgnd
    
  7. Создайте элемент управления редактирования в диалоговом окне, а затем подключите его к переменной-члену, дважды щелкнув элемент управления редактированием при удержании ключа элемента управления вниз. В диалоговом окне "Добавление переменной элемента" завершите имя переменной и выберите "Control" для категории, а затем "CYellowEdit" для типа переменной. Не забудьте задать порядок вкладок в диалоговом окне. Кроме того, не забудьте включить файл заголовка элемента CYellowEdit управления в файл заголовка диалогового окна.

  8. Скомпилируйте и запустите приложение. Элемент управления редактирования будет иметь желтый фон.

См. также

Технические примечания по номеру
Технические примечания по категории