TN061. Сообщения ON_NOTIFY и WM_NOTIFY

Примечание.

Следующее техническое примечание не было обновлено, поскольку сначала оно было включено в электронную документацию. В результате некоторые процедуры и разделы могут быть устаревшими или неверными. Для получения последних сведений рекомендуется выполнить поиск интересующей темы в алфавитном указателе документации в Интернете.

Эта техническая заметка содержит справочную информацию о новом сообщении WM_NOTIFY и описывает рекомендуемый (и наиболее распространенный) способ обработки WM_NOTIFY сообщений в приложении MFC.

Сообщения уведомлений в Windows 3.x

В Windows 3.x элементы управления уведомляют своих родителей о событиях, таких как щелчки мыши, изменения в содержимом и выборе, а также управление фоновым рисунком, отправив родительскому сообщению сообщение. Простые уведомления отправляются в виде специальных WM_COMMAND сообщений с кодом уведомления (например, BN_CLICKED) и идентификатором элемента управления, упакованным в wParam и дескриптор элемента управления в lParam. Обратите внимание, что так как wParam и lParam полны, нет способа передать дополнительные данные — эти сообщения могут быть только простым уведомлением. Например, в уведомлении BN_CLICKED нет способа отправлять сведения о расположении курсора мыши при нажатии кнопки.

Если элементы управления в Windows 3.x должны отправлять уведомление, включающее дополнительные данные, они используют различные специальные сообщения, включая WM_CTLCOLOR, WM_VSCROLL, WM_HSCROLL, WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM, WM_DELETEITEM, WM_CHARTOITEM, WM_VKEYTOITEM и т. д. Эти сообщения можно отражать обратно в элемент управления, отправляемый им. Дополнительные сведения см. в разделе TN062: сообщение Рефлексия ion для элементов управления Windows.

Сообщения уведомлений в Win32

Для элементов управления, существующих в Windows 3.1, API Win32 использует большинство сообщений уведомлений, которые использовались в Windows 3.x. Однако Win32 также добавляет ряд сложных, сложных элементов управления для тех, которые поддерживаются в Windows 3.x. Часто эти элементы управления должны отправлять дополнительные данные с их сообщениями уведомления. Вместо добавления нового сообщения WM_* для каждого нового уведомления, требующего дополнительных данных, конструкторы API Win32 решили добавить только одно сообщение, WM_NOTIFY, которое может передавать любой объем дополнительных данных в стандартизованном виде.

WM_NOTIFY сообщения содержат идентификатор элемента управления, отправляющего сообщение в wParam, и указатель на структуру в lParam. Эта структура представляет собой структуру NMHDR или некоторую большую структуру, которая имеет структуру NMHDR в качестве первого элемента. Обратите внимание, что так как элемент NMHDR является первым, указатель на эту структуру можно использовать как указатель на NMHDR или в качестве указателя на большую структуру в зависимости от способа его приведения.

В большинстве случаев указатель будет указывать на большую структуру, и вам потребуется привести ее при использовании. В некоторых уведомлениях, таких как распространенные уведомления (имена которых начинаются с NM_) и TTN_SHOW и TTN_POP уведомления элемента управления подсказками, фактически используется структура NMHDR .

Структура NMHDR или начальный элемент содержит дескриптор и идентификатор элемента управления, отправляющего сообщение, и код уведомления (например, TTN_SHOW). Ниже показан формат структуры NMHDR :

typedef struct tagNMHDR {
    HWND hwndFrom;
    UINT idFrom;
    UINT code;
} NMHDR;

Для сообщения TTN_SHOW для элемента кода будет задано значение TTN_SHOW.

Большинство уведомлений передают указатель на большую структуру, содержащую структуру NMHDR в качестве первого члена. Например, рассмотрим структуру, используемую LVN_KEYDOWN сообщением элемента управления представлением списка, которое отправляется при нажатии клавиши в элементе управления представлением списка. Указатель указывает на структуру LV_KEYDOWN , которая определена, как показано ниже:

typedef struct tagLV_KEYDOWN {
    NMHDR hdr;
    WORD wVKey;
    UINT flags;
} LV_KEYDOWN;

Обратите внимание, что так как элемент NMHDR впервые находится в этой структуре, указатель, передаваемый в сообщении уведомления, можно привести к указателю на NMHDR или указатель на LV_KEYDOWN.

Уведомления, общие для всех новых элементов управления Windows

Некоторые уведомления являются общими для всех новых элементов управления Windows. Эти уведомления передают указатель на структуру NMHDR .

Код уведомления Отправлено, так как
NM_CLICK Нажатой пользователем левой кнопкой мыши в элементе управления
NM_DBLCLK Пользователь дважды щелкнул левую кнопку мыши в элементе управления
NM_RCLICK Пользователь щелкнул правую кнопку мыши в элементе управления
NM_RDBLCLK Дважды щелкнув правой кнопкой мыши пользователя в элементе управления
NM_RETURN Пользователь нажимал клавишу ВВОД, а элемент управления имеет фокус ввода
NM_SETFOCUS Элемент управления был задан фокус на входных данных
NM_KILLFOCUS Элемент управления потерял фокус ввода
NM_OUTOFMEMORY Управление не удалось завершить операцию, так как недостаточно памяти

ON_NOTIFY. Обработка сообщений WM_NOTIFY в приложениях MFC

Функция CWnd::OnNotify обрабатывает сообщения уведомлений. Его реализация по умолчанию проверка сопоставление сообщений для обработчиков уведомлений для вызова. Как правило, вы не переопределяете OnNotify. Вместо этого вы предоставляете функцию обработчика и добавляете запись карты сообщений для этого обработчика в карту сообщений класса окна владельца.

ClassWizard с помощью листа свойств ClassWizard может создать запись ON_NOTIFY карты сообщений и предоставить вам функцию обработчика скелета. Дополнительные сведения об использовании ClassWizard для упрощения работы см. в разделе "Сопоставление сообщений с функциями".

Макрос карты сообщений ON_NOTIFY имеет следующий синтаксис:

ON_NOTIFY(wNotifyCode, id, memberFxn)

Используются следующие параметры.

wNotifyCode
Код для обработки сообщения уведомления, например LVN_KEYDOWN.

id
Дочерний идентификатор элемента управления, для которого отправляется уведомление.

memberFxn
Функция-член, вызываемая при отправке этого уведомления.

Функция-член должна быть объявлена со следующим прототипом:

afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);

Используются следующие параметры.

pNotifyStruct
Указатель на структуру уведомлений, как описано в приведенном выше разделе.

result
Указатель на код результата, который вы задали перед возвратом.

Пример

Чтобы указать, что функция-член будет обрабатывать сообщения LVN_KEYDOWN из идентификатора CListCtrlIDC_LIST1, можно использовать ClassWizard, чтобы добавить следующую функцию OnKeydownList1 в карту сообщений:

ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)

В приведенном выше примере функция, предоставляемая ClassWizard:

void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;

    // TODO: Add your control notification handler
    //       code here

    *pResult = 0;
}

Обратите внимание, что ClassWizard предоставляет указатель правильного типа автоматически. Вы можете получить доступ к структуре уведомлений через pNMHDR или pLVKeyDow.

ON_NOTIFY_RANGE

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

При использовании ON_NOTIFY_RANGE укажите непрерывный диапазон дочерних идентификаторов, для которых нужно обрабатывать сообщение уведомления, указав начальные и конечные дочерние идентификаторы диапазона.

ClassWizard не обрабатывает ON_NOTIFY_RANGE; чтобы использовать его, необходимо самостоятельно изменить карту сообщений.

Прототип записи и функции карты сообщений для ON_NOTIFY_RANGE выглядит следующим образом:

ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn)

Используются следующие параметры.

wNotifyCode
Код для обработки сообщения уведомления, например LVN_KEYDOWN.

id
Первый идентификатор в непрерывном диапазоне идентификаторов.

idLast
Последний идентификатор в непрерывном диапазоне идентификаторов.

memberFxn
Функция-член, вызываемая при отправке этого уведомления.

Функция-член должна быть объявлена со следующим прототипом:

afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);

Используются следующие параметры.

id
Дочерний идентификатор элемента управления, отправляющего уведомление.

pNotifyStruct
Указатель на структуру уведомлений, как описано выше.

result
Указатель на код результата, который вы задали перед возвратом.

ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE

Если для обработки сообщения требуется несколько объектов в маршрутизации уведомлений, можно использовать ON_NOTIFY_EX (или ON_NOTIFY_EX_RANGE), а не ON_NOTIFY (или ON_NOTIFY_RANGE). Единственное различие между версией EX и обычной версией заключается в том, что функция-член, вызываемая для версии EX , возвращает ЛОГИЧЕСКОЕ значение, указывающее, следует ли продолжать обработку сообщений. Возврат FALSE из этой функции позволяет обрабатывать одно и то же сообщение в нескольких объектах.

КлассWizard не обрабатывает ON_NOTIFY_EX или ON_NOTIFY_EX_RANGE; Если вы хотите использовать любой из них, необходимо самостоятельно изменить карту сообщений.

Прототип записи и функции карты сообщений для ON_NOTIFY_EX и ON_NOTIFY_EX_RANGE приведены ниже. Значения параметров совпадают с значениями версий, отличных от EX .

ON_NOTIFY_EX(nCode, id, memberFxn)
ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn)

Прототип для обоих из указанных выше вариантов совпадает:

afx_msg BOOL memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);

В обоих случаях идентификатор содержит дочерний идентификатор элемента управления, отправляющего уведомление.

Функция должна возвращать значение TRUE , если сообщение уведомления было полностью обработано или FALSE , если другие объекты в маршрутизации команд должны иметь возможность обрабатывать сообщение.

См. также

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