TN061 : messages ON_NOTIFY et WM_NOTIFY
Remarque
La note technique suivante n'a pas été mise à jour depuis son inclusion initiale dans la documentation en ligne. Par conséquent, certaines procédures et rubriques peuvent être obsolètes ou incorrectes. Pour obtenir les informations les plus récentes, il est recommandé de rechercher l'objet qui vous intéresse dans l'index de la documentation en ligne.
Cette note technique fournit des informations générales sur le nouveau message WM_NOTIFY et décrit la façon recommandée (et la plus courante) de gérer les messages WM_NOTIFY dans votre application MFC.
Messages de notification dans Windows 3.x
Dans Windows 3.x, les contrôles informent leurs parents d’événements tels que les clics de souris, les modifications apportées au contenu et la sélection, et contrôlent la peinture en arrière-plan en envoyant un message au parent. Les notifications simples sont envoyées en tant que messages WM_COMMAND spéciaux, avec le code de notification (par exemple, BN_CLICKED) et l’ID de contrôle empaquetés dans wParam et le handle du contrôle dans lParam. Notez que, étant donné que wParam et lParam sont pleins, il n’existe aucun moyen de transmettre des données supplémentaires : ces messages ne peuvent être que des notifications simples. Par exemple, dans la notification BN_CLICKED, il n’existe aucun moyen d’envoyer des informations sur l’emplacement du curseur de la souris lorsque le bouton a été cliqué.
Lorsque les contrôles dans Windows 3.x doivent envoyer un message de notification qui inclut des données supplémentaires, ils utilisent divers messages à usage spécial, notamment WM_CTLCOLOR, WM_VSCROLL, WM_HSCROLL, WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM, WM_DELETEITEM, WM_CHARTOITEM, WM_VKEYTOITEM, et ainsi de suite. Ces messages peuvent être répercutés sur le contrôle qui les a envoyés. Pour plus d’informations, consultez TN062 : Message Réflexions ion pour les contrôles Windows.
Messages de notification dans Win32
Pour les contrôles qui existaient dans Windows 3.1, l’API Win32 utilise la plupart des messages de notification utilisés dans Windows 3.x. Toutefois, Win32 ajoute également un certain nombre de contrôles complexes et sophistiqués à ceux pris en charge dans Windows 3.x. Fréquemment, ces contrôles doivent envoyer des données supplémentaires avec leurs messages de notification. Au lieu d’ajouter un nouveau message WM_* pour chaque nouvelle notification nécessitant des données supplémentaires, les concepteurs de l’API Win32 ont choisi d’ajouter un seul message, WM_NOTIFY, qui peut transmettre toute quantité de données supplémentaires de manière standardisée.
WM_NOTIFY messages contiennent l’ID du contrôle envoyant le message dans wParam et un pointeur vers une structure dans lParam. Cette structure est une structure NMHDR ou une structure plus grande qui a une structure NMHDR en tant que premier membre. Notez que, étant donné que le membre NMHDR est d’abord, un pointeur vers cette structure peut être utilisé comme pointeur vers un NMHDR ou comme pointeur vers la structure plus grande en fonction de la façon dont vous le castez.
Dans la plupart des cas, le pointeur pointe vers une structure plus grande et vous devez le caster lorsque vous l’utilisez. Dans seulement quelques notifications, telles que les notifications courantes (dont les noms commencent par NM_) et le TTN_SHOW du contrôle info-bulle et les notifications TTN_POP, est une structure NMHDR réellement utilisée.
La structure NMHDR ou le membre initial contient le handle et l’ID du contrôle envoyant le message et le code de notification (par exemple, TTN_SHOW). Le format de la structure NMHDR est indiqué ci-dessous :
typedef struct tagNMHDR {
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR;
Pour un message TTN_SHOW, le membre de code est défini sur TTN_SHOW.
La plupart des notifications passent un pointeur vers une structure plus grande qui contient une structure NMHDR en tant que premier membre. Par exemple, considérez la structure utilisée par le message de notification LVN_KEYDOWN du contrôle d’affichage de liste, qui est envoyé lorsqu’une touche est enfoncée dans un contrôle d’affichage de liste. Le pointeur pointe vers une structure LV_KEYDOWN , qui est définie comme indiqué ci-dessous :
typedef struct tagLV_KEYDOWN {
NMHDR hdr;
WORD wVKey;
UINT flags;
} LV_KEYDOWN;
Notez que, étant donné que le membre NMHDR est d’abord dans cette structure, le pointeur que vous passez dans le message de notification peut être converti en pointeur vers un NMHDR ou un pointeur vers un LV_KEYDOWN.
Notifications communes à tous les nouveaux contrôles Windows
Certaines notifications sont communes à tous les nouveaux contrôles Windows. Ces notifications passent un pointeur vers une structure NMHDR .
Code de notification | Envoyé parce que |
---|---|
NM_CLICK | L’utilisateur a cliqué sur le bouton gauche de la souris dans le contrôle |
NM_DBLCLK | Bouton de la souris gauche double-cliqué sur l’utilisateur dans le contrôle |
NM_RCLICK | L’utilisateur a cliqué sur le bouton droit de la souris dans le contrôle |
NM_RDBLCLK | Bouton droit de la souris double-cliqué sur l’utilisateur dans le contrôle |
NM_RETURN | L’utilisateur a appuyé sur la touche Entrée pendant que le contrôle a le focus d’entrée |
NM_SETFOCUS | Le contrôle a reçu le focus d’entrée |
NM_KILLFOCUS | Le contrôle a perdu le focus d’entrée |
NM_OUTOFMEMORY | Le contrôle n’a pas pu terminer une opération, car il n’y avait pas suffisamment de mémoire disponible |
ON_NOTIFY : gestion des messages WM_NOTIFY dans les applications MFC
La fonction CWnd::OnNotify
gère les messages de notification. Son implémentation par défaut case activée le mappage de messages pour les gestionnaires de notification à appeler. En général, vous ne remplacez OnNotify
pas . Au lieu de cela, vous fournissez une fonction de gestionnaire et ajoutez une entrée de mappage de message pour ce gestionnaire à la carte de messages de la classe de la fenêtre propriétaire.
ClassWizard, via la feuille de propriétés ClassWizard, peut créer l’entrée de carte de messages ON_NOTIFY et vous fournir une fonction de gestionnaire de squelettes. Pour plus d’informations sur l’utilisation de ClassWizard pour faciliter ce processus, consultez Mappage de messages à fonctions.
La macro de mappage de messages ON_NOTIFY a la syntaxe suivante :
ON_NOTIFY(wNotifyCode, id, memberFxn)
où les paramètres sont :
wNotifyCode
Code du message de notification à gérer, tel que LVN_KEYDOWN.
id
Identificateur enfant du contrôle pour lequel la notification est envoyée.
memberFxn
Fonction membre à appeler lorsque cette notification est envoyée.
Votre fonction membre doit être déclarée avec le prototype suivant :
afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);
où les paramètres sont :
pNotifyStruct
Pointeur vers la structure de notification, comme décrit dans la section ci-dessus.
result
Pointeur vers le code de résultat que vous allez définir avant de retourner.
Exemple
Pour spécifier que vous souhaitez que la fonction OnKeydownList1
membre gère LVN_KEYDOWN messages à partir de l’ID CListCtrl
dont l’ID est IDC_LIST1
, vous devez utiliser ClassWizard pour ajouter les éléments suivants à votre carte de messages :
ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)
Dans l’exemple ci-dessus, la fonction fournie par ClassWizard est la suivante :
void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;
// TODO: Add your control notification handler
// code here
*pResult = 0;
}
Notez que ClassWizard fournit automatiquement un pointeur du type approprié. Vous pouvez accéder à la structure de notification via pNMHDR ou pLVKeyDow.
ON_NOTIFY_RANGE
Si vous devez traiter le même message WM_NOTIFY pour un ensemble de contrôles, vous pouvez utiliser ON_NOTIFY_RANGE plutôt que ON_NOTIFY. Par exemple, vous pouvez avoir un ensemble de boutons pour lesquels vous souhaitez effectuer la même action pour un certain message de notification.
Lorsque vous utilisez ON_NOTIFY_RANGE, vous spécifiez une plage contiguë d’identificateurs enfants pour lesquels gérer le message de notification en spécifiant les identificateurs enfants de début et de fin de la plage.
ClassWizard ne gère pas ON_NOTIFY_RANGE ; pour l’utiliser, vous devez modifier votre carte de messages vous-même.
L’entrée de carte de messages et le prototype de fonction pour ON_NOTIFY_RANGE sont les suivants :
ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn)
où les paramètres sont :
wNotifyCode
Code du message de notification à gérer, tel que LVN_KEYDOWN.
id
Premier identificateur dans la plage contiguë d’identificateurs.
idLast
Dernier identificateur de la plage contiguë d’identificateurs.
memberFxn
Fonction membre à appeler lorsque cette notification est envoyée.
Votre fonction membre doit être déclarée avec le prototype suivant :
afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
où les paramètres sont :
id
Identificateur enfant du contrôle qui a envoyé la notification.
pNotifyStruct
Pointeur vers la structure de notification, comme décrit ci-dessus.
result
Pointeur vers le code de résultat que vous allez définir avant de retourner.
ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE
Si vous souhaitez que plusieurs objets du routage de notification gèrent un message, vous pouvez utiliser ON_NOTIFY_EX (ou ON_NOTIFY_EX_RANGE) plutôt que ON_NOTIFY (ou ON_NOTIFY_RANGE). La seule différence entre la version EX et la version régulière est que la fonction membre appelée pour la version EX retourne un BOOL qui indique si le traitement des messages doit continuer ou non. Le renvoi de FALSE à partir de cette fonction vous permet de traiter le même message dans plusieurs objets.
ClassWizard ne gère pas ON_NOTIFY_EX ni ON_NOTIFY_EX_RANGE ; si vous souhaitez utiliser l’un ou l’autre d’entre eux, vous devez modifier votre carte de messages vous-même.
L’entrée de carte de messages et le prototype de fonction pour ON_NOTIFY_EX et ON_NOTIFY_EX_RANGE sont les suivants. Les significations des paramètres sont les mêmes que pour les versions non EX.
ON_NOTIFY_EX(nCode, id, memberFxn)
ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn)
Le prototype pour les deux versions ci-dessus est le même :
afx_msg BOOL memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
Dans les deux cas, l’ID contient l’identificateur enfant du contrôle qui a envoyé la notification.
Votre fonction doit retourner TRUE si le message de notification a été complètement géré ou FALSE si d’autres objets du routage de commandes doivent avoir la possibilité de gérer le message.