TN061: Mensajes ON_NOTIFY y WM_NOTIFY
Nota:
La nota técnica siguiente no se ha actualizado desde que se incluyó por primera vez en la documentación en línea. Como resultado, algunos procedimientos y temas podrían estar obsoletos o ser incorrectos. Para obtener información más reciente, se recomienda buscar el tema de interés en el índice de la documentación en línea.
Esta nota técnica proporciona información general sobre el nuevo mensaje WM_NOTIFY y describe la forma recomendada (y más común) de controlar los mensajes WM_NOTIFY en la aplicación MFC.
Mensajes de notificación en Windows 3.x
En Windows 3.x, los controles notifican a sus elementos primarios eventos, como los clics del mouse, los cambios en el contenido y la selección, y controlan la pintura del fondo mediante el envío de un mensaje al elemento primario. Las notificaciones simples se envían como mensajes WM_COMMAND especiales, con el código de notificación (como BN_CLICKED) y el identificador del control empaquetados en wParam y el manipulador del control en lParam. Tenga en cuenta que, dado que wParam y lParam están llenos, no hay ninguna manera de pasar datos adicionales, estos mensajes solo pueden ser notificaciones simples. Por ejemplo, en la notificación BN_CLICKED, no hay forma de enviar información sobre la ubicación del cursor del mouse cuando se hizo clic en el botón.
Cuando los controles de Windows 3.x tienen que enviar un mensaje de notificación que incluya datos adicionales, usan una variedad de mensajes de propósito especial, como WM_CTLCOLOR, WM_VSCROLL, WM_HSCROLL, WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM, WM_DELETEITEM, WM_CHARTOITEM, WM_VKEYTOITEM, etc. Estos mensajes se pueden reflejar de nuevo al control que los envió. Para más información, consulte TN062: Reflexión de mensajes para controles de Windows.
Mensajes de notificación en Win32
Para los controles que existían en Windows 3.1, la API de Win32 usa la mayoría de los mensajes de notificación que se usaban en Windows 3.x. Sin embargo, Win32 también agrega una serie de controles complejos y sofisticados a los admitidos en Windows 3.x. Con frecuencia, estos controles deben enviar datos adicionales con sus mensajes de notificación. En lugar de agregar un nuevo mensaje WM_* para cada nueva notificación que necesite datos adicionales, los diseñadores de la API de Win32 optaron por agregar un solo mensaje, WM_NOTIFY, que puede pasar cualquier cantidad de datos adicionales de forma estandarizada.
Los mensajes WM_NOTIFY contienen el identificador del control que envía el mensaje en wParam y un puntero a una estructura en lParam. Esta estructura es una estructura NMHDR o una estructura más grande que tiene una estructura NMHDR como su primer miembro. Tenga en cuenta que, dado que el miembro NMHDR es el primero, se puede usar un puntero a esta estructura como puntero a un elemento NMHDR o como puntero a la estructura más grande en función de cómo lo convierta.
En la mayoría de los casos, el puntero apuntará a una estructura más grande y tendrá que convertirlo cuando lo use. En solo algunas notificaciones, como las notificaciones comunes (cuyos nombres comienzan por NM_) y las notificaciones TTN_SHOW y TTN_POP del control de información sobre herramientas, se usa realmente una estructura NMHDR.
La estructura NMHDR o el miembro inicial contienen el manipulador y el identificador del control que envía el mensaje, y el código de notificación (por ejemplo, TTN_SHOW). A continuación, se muestra el formato de la estructura NMHDR:
typedef struct tagNMHDR {
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR;
Para un mensaje TTN_SHOW, el miembro code se establecería en TTN_SHOW.
La mayoría de las notificaciones pasan un puntero a una estructura más grande que contiene una estructura NMHDR como su primer miembro. Por ejemplo, considere la estructura utilizada por el mensaje de notificación LVN_KEYDOWN del control de vista de lista, que se envía cuando se pulsa una tecla en un control de vista de lista. El puntero apunta a una estructura LV_KEYDOWN, que se define como se muestra a continuación:
typedef struct tagLV_KEYDOWN {
NMHDR hdr;
WORD wVKey;
UINT flags;
} LV_KEYDOWN;
Tenga en cuenta que, dado que el miembro NMHDR es el primero en esta estructura, el puntero que se pasa en el mensaje de notificación se puede convertir a un puntero a un elemento NMHDR o a un puntero a un elemento LV_KEYDOWN.
Notificaciones comunes a todos los nuevos controles de Windows
Algunas notificaciones son comunes a todos los nuevos controles de Windows. Estas notificaciones pasan un puntero a una estructura NMHDR.
Código de notificación | Enviado porque |
---|---|
NM_CLICK | El usuario ha hecho clic en el botón izquierdo del mouse en el control. |
NM_DBLCLK | El usuario ha hecho doble clic en el botón izquierdo del mouse en el control. |
NM_RCLICK | El usuario ha hecho clic en el botón derecho del mouse en el control. |
NM_RDBLCLK | El usuario ha hecho doble clic en el botón derecho del mouse en el control. |
NM_RETURN | El usuario ha pulsado la tecla ENTRAR mientras el control tiene el foco de entrada. |
NM_SETFOCUS | Se ha proporcionado el foco de entrada al control. |
NM_KILLFOCUS | El control ha perdido el foco de entrada. |
NM_OUTOFMEMORY | El control no pudo completar una operación porque no hay suficiente memoria disponible. |
ON_NOTIFY: control de mensajes WM_NOTIFY en aplicaciones MFC
La función CWnd::OnNotify
controla los mensajes de notificación. Su implementación predeterminada comprueba el mapa de mensajes para que los controladores de notificaciones realicen las llamadas. En general, no se invalida OnNotify
. En su lugar, se proporciona una función de controlador y se agrega una entrada de mapa de mensajes para ese controlador al mapa de mensajes de la clase de la ventana propietaria.
ClassWizard, mediante la hoja de propiedades de ClassWizard, puede crear la entrada de mapa de mensajes de ON_NOTIFY y proporcionarle el esqueleto de una función de controlador. Para obtener más información sobre el uso de ClassWizard para facilitar esta tarea, consulte Asignar mensajes a funciones.
La macro de mapa de mensajes de ON_NOTIFY tiene la sintaxis siguiente:
ON_NOTIFY(wNotifyCode, id, memberFxn)
donde los parámetros son:
wNotifyCode
Código para que se controle el mensaje de notificación, por ejemplo, LVN_KEYDOWN.
id
Identificador secundario del control para el que se envía la notificación.
memberFxn
Función miembro a la que se llamará cuando se envíe esta notificación.
La función miembro se sebe declarar con el prototipo siguiente:
afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);
donde los parámetros son:
pNotifyStruct
Puntero a la estructura de notificaciones, como se describe en la sección anterior.
result
Puntero al código de resultado que va a establecer antes de volver.
Ejemplo
Para especificar que desea que la función miembro OnKeydownList1
controle los mensajes LVN_KEYDOWN del elemento CListCtrl
cuyo identificador es IDC_LIST1
, usaría ClassWizard para agregar lo siguiente al mapa de mensajes:
ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)
En el ejemplo anterior, la función proporcionada por ClassWizard es:
void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;
// TODO: Add your control notification handler
// code here
*pResult = 0;
}
Tenga en cuenta que ClassWizard proporciona automáticamente un puntero del tipo adecuado. Puede acceder a la estructura de notificaciones mediante pNMHDR o pLVKeyDow.
ON_NOTIFY_RANGE
Si tiene que procesar el mismo mensaje WM_NOTIFY para un conjunto de controles, puede usar ON_NOTIFY_RANGE en lugar de ON_NOTIFY. Por ejemplo, puede tener un conjunto de botones para los que desea realizar la misma acción para un mensaje de notificación determinado.
Al usar ON_NOTIFY_RANGE, especifique un intervalo contiguo de identificadores secundarios para los que controlar el mensaje de notificación especificando los identificadores secundarios inicial y final del intervalo.
ClassWizard no controla ON_NOTIFY_RANGE; para usarlo, debe editar el mapa de mensajes usted mismo.
El prototipo de función y la entrada de mapa de mensajes para ON_NOTIFY_RANGE son los siguientes:
ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn)
donde los parámetros son:
wNotifyCode
Código para que se controle el mensaje de notificación, por ejemplo, LVN_KEYDOWN.
id
Primer identificador del intervalo contiguo de identificadores.
idLast
Último identificador del intervalo contiguo de identificadores.
memberFxn
Función miembro a la que se llamará cuando se envíe esta notificación.
La función miembro se sebe declarar con el prototipo siguiente:
afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
donde los parámetros son:
id
El identificador secundario del control que ha enviado la notificación.
pNotifyStruct
Puntero a la estructura de notificaciones, como se describe en la sección anterior.
result
Puntero al código de resultado que va a establecer antes de volver.
ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE
Si desea que más de un objeto del enrutamiento de notificaciones controle un mensaje, puede usar ON_NOTIFY_EX (u ON_NOTIFY_EX_RANGE) en lugar de ON_NOTIFY (u ON_NOTIFY_RANGE). La única diferencia entre la versión EX y la versión normal es que la función miembro a la que se llama para la versión EX devuelve un valor BOOL que indica si el procesamiento de mensajes debe continuar o no. Devolver FALSE desde esta función le permite procesar el mismo mensaje en más de un objeto.
ClassWizard no controla ON_NOTIFY_EX ni ON_NOTIFY_EX_RANGE; si desea usar cualquiera de ellos, debe editar el mapa de mensajes usted mismo.
El prototipo de función y la entrada de mapa de mensajes para ON_NOTIFY_EX y ON_NOTIFY_EX_RANGE son los siguientes. Los significados de los parámetros son los mismos que para las versiones que no son EX.
ON_NOTIFY_EX(nCode, id, memberFxn)
ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn)
El prototipo para ambos de los anteriores es el mismo:
afx_msg BOOL memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
En ambos casos, id contiene el identificador secundario del control que ha enviado la notificación.
La función debe devolver TRUE si el mensaje de notificación se ha controlado completamente o FALSE si otros objetos del enrutamiento de comandos deben tener la oportunidad de controlar el mensaje.