TN062 : renvoi de message pour des contrôles Windows
Notes
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 décrit le renvoi de message, une nouvelle fonctionnalité de MFC 4,0. Elle contient également des instructions pour créer un contrôle réutilisable simple qui utilise le renvoi de message.
Cette note technique ne présente pas le renvoi de message à mesure qu'il applique aux contrôles ActiveX (anciennement appelé les contrôles OLE). Consultez l'article Contrôles ActiveX : Sous-classement un contrôle Windows.
Quel est le message renvoyé ?
Les contrôles Windows envoient fréquemment des messages de notification vers les fenêtres parentes. Par exemple, de nombreuses commandes envoient un message de notification de couleur (WM_CTLCOLOR ou une de ses variantes) à leur parents pour leur fournir un pinceau pour peindre l'arrière-plan de la commande.
Dans windows et dans MFC avant la version 4,0, la fenêtre parente, souvent une boîte de dialogue, est chargée de gérer les messages. Cela signifie que le code pour la gestion du message doit être dans la classe parente de la fenêtre et qu'il doit être dupliqué dans chaque classe qui doit traiter ce message. Dans le cas ci-dessus, chaque boîte de dialogue que les commandes souhaitées d'arrière-plan personnalisés doit traiter le message de notification de couleur. Il est beaucoup plus facile de réutiliser le code s'il peut écrire une classe de contrôle qui gèrerait sa propre couleur d'arrière-plan.
Dans MFC 4,0, l'ancien mécanisme fonctionne toujours — les fenêtres parentes peuvent traiter les messages de notification. En outre, toutefois, MFC 4,0 facilite la réutilisation en fournissant une fonctionnalité appelée « renvoi de message » qui autorise les messages de notification à être gérés dans la fenêtre de commande enfant ou la fenêtre parente, ou dans les deux. Dans l'exemple de couleur d'arrière-plan, vous pouvez désormais écrire une classe de contrôle qui définit sa propre couleur d'arrière-plan en gérant le message renvoyé WM_CTLCOLOR — tout ça sans compter sur l'objet parent. Notez que le renvoi de message est implémentée par MFC, et non par Wndows, la classe de la fenêtre parente doit être dérivée de CWnd pour que le renvoi de messages fonctionne.)
Les versions antérieures de MFC faisaient quelque chose de semblable pour le renvoi de message en fournissant des fonctions virtuelles pour certains messages, tels que les messages des zones de liste owner-drawn (WM_DRAWITEM, etc.). Le nouveau mécanisme de renvoi de message est généralisé et cohérent.
Le renvoi de message est une compatibilité descendante complète avec le code écrit pour les versions de MFC avant 4,0.
Si vous avez fourni un gestionnaire d'un message spécifique, ou pour une série de messages, dans la classe parente de la fenêtre, cela remplacera les gestionnaires de messages renvoyés par le même message si vous n'appelez pas la fonction gestionnaire de classe de base dans votre propre gestionnaire. Par exemple, si vous gérez WM_CTLCOLOR dans la classe de la boîte de dialogue, votre gestion remplace tous les gestionnaires de messages apparaissent.
Si, dans la classe fenêtre parente, vous devez fournir un gestionnaire d'un message spécifique de WM_NOTIFY ou d'une chaîne de message WM_NOTIFY, votre gestionnaire est appelé uniquement si le contrôle enfant de ces messages n'a pas de gestionnaire de messages en miroir par ON_NOTIFY_REFLECT(). Si vous utilisez ON_NOTIFY_REFLECT_EX() dans la table des messages, votre gestionnaire de messages peut autoriser ou ne pas autoriser la fenêtre parente pour traiter le message. Si le gestionnaire renvoie FALSE, le message est également traité par le parent, tandis qu'un appel qui renvoie TRUE ne permet pas au parent de le gérer. Notez que le message en miroir est traité avant le message de notification.
Lorsqu'un message de WM_NOTIFY est envoyé, la commande se voit proposer la première occasion pour la gérer. Si tout autre message en miroir est envoyé, la fenêtre parente a la première occasion de la gérer et la commande recevra le message en miroir. Pour ce faire, il a besoin d'une fonction gestionnaire et une entrée appropriée dans la table des messages de la classe de la commande.
La macro table des messages pour les messages renvoyés est légèrement différente pour les notifications normales : elle a _REFLECT ajouté à son nom habituel. Par exemple, pour traiter un message WM_NOTIFY du parent, utilisez la macro ON_NOTIFY dans la table des messages du parent. Pour traiter le message en miroir dans le contrôle enfant, utilisez la macro ON_NOTIFY_REFLECT dans la table des messages du contrôle enfant. Dans certains cas, les paramètres sont différents. Notez que ClassWizard peut généralement ajouter des entrées de la table des messages pour vous et fournir des implémentations de squelettes de fonctions avec les paramètres corrects.
Consultez TN061 : Messages d'ON_NOTIFY et de WM_NOTIFY pour plus d'informations sur le nouveau message de WM_NOTIFY.
Entrées de la table des messages et les prototypes de fonction gestionnaire des messages renvoyés
Pour traiter un message de notification de contrôle en miroir, utilisez les macros table de messages et les prototypes de fonctions répertoriées dans le tableau ci-dessous.
ClassWizard peut généralement ajouter ces entrées de la table des messages pour vous et fournir des implémentations de squelettes de fonctions. Consultez Définir un gestionnaire de messages d'un message en miroir pour plus d'informations sur la définition des gestionnaires des messages renvoyés.
Pour convertir à partir du message vers le nom de la macro en miroir, ajoutez ON_ et ajoutez _REFLECT. Par exemple, WM_CTLCOLOR devient ON_WM_CTLCOLOR_REFLECT. (Pour voir quels messages peuvent être renvoyés, effectuez une conversion inverse sur les macro entrées dans la table ci-dessous.)
Les trois exceptions à cette règle ci-dessus sont les suivantes :
La macro pour les notifications WM_COMMAND est ON_CONTROL_REFLECT.
La macro des réflexions WM_NOTIFY est ON_NOTIFY_REFLECT.
La macro des réflexions ON_UPDATE_COMMAND_UI est ON_UPDATE_COMMAND_UI_REFLECT.
Dans les cas individuels ci-dessus, vous devez spécifier le nom de la fonction membre gestionnaire. Dans les autres cas, vous devez utiliser le nom standard pour la fonction gestionnaire.
Les significations des paramètres et des valeurs de résultats des fonctions sont documentées soit dans le nom de fonction soit dans le nom de la fonction avec On ajouté. Par exemple, CtlColor est documenté dans OnCtlColor. Plusieurs gestionnaires de messages renvoyés requièrent moins de paramètres que les gestionnaires similaires dans une fenêtre parente. Correspondance uniquement entre les noms dans le tableau ci-dessous avec les noms des paramètres formels dans la documentation.
Entrée de mappage |
Prototype de fonction |
---|---|
ON_CONTROL_REFLECT( wNotifyCode, memberFxn ) |
afx_msg void memberFxn ( ); |
ON_NOTIFY_REFLECT( wNotifyCode, memberFxn ) |
afx_msg void memberFxn ( NMHDR * pNotifyStruct, LRESULT* résultat ); |
ON_UPDATE_COMMAND_UI_REFLECT( memberFxn ) |
afx_msg void memberFxn ( CCmdUI* pCmdUI ); |
ON_WM_CTLCOLOR_REFLECT( ) |
afx_msg HBRUSH CtlColor ( CDC* pDC, UINT nCtlColor ); |
ON_WM_DRAWITEM_REFLECT( ) |
afx_msg void DrawItem ( LPDRAWITEMSTRUCT lpDrawItemStruct ); |
ON_WM_MEASUREITEM_REFLECT( ) |
afx_msg void MeasureItem ( LPMEASUREITEMSTRUCT lpMeasureItemStruct ); |
ON_WM_DELETEITEM_REFLECT( ) |
afx_msg void DeleteItem ( LPDELETEITEMSTRUCT lpDeleteItemStruct ); |
ON_WM_COMPAREITEM_REFLECT( ) |
afx_msg int CompareItem ( LPCOMPAREITEMSTRUCT lpCompareItemStruct ); |
ON_WM_CHARTOITEM_REFLECT( ) |
afx_msg int CharToItem ( UINT nKey, UINT nIndex ); |
ON_WM_VKEYTOITEM_REFLECT( ) |
afx_msg int VKeyToItem ( UINT nKey, UINT nIndex ); |
ON_WM_HSCROLL_REFLECT( ) |
afx_msg void HScroll ( UINT nSBCode, UINT nPos ); |
ON_WM_VSCROLL_REFLECT( ) |
afx_msg void VScroll ( UINT nSBCode, UINT nPos ); |
ON_WM_PARENTNOTIFY_REFLECT () |
afx_msg void ParentNotify ( UINT message, LPARAM lParam ); |
Les macros ON_NOTIFY_REFLECT et ON_CONTROL_REFLECT sont des variations qui permettent à plusieurs objets (telles que la commande et son parent) pour traiter un message donné.
Entrée de mappage |
Prototype de fonction |
---|---|
ON_NOTIFY_REFLECT_EX( wNotifyCode, memberFxn ) |
afx_msg BOOL memberFxn ( NMHDR * pNotifyStruct, LRESULT* résultat ); |
ON_CONTROL_REFLECT_EX( wNotifyCode, memberFxn ) |
afx_msg BOOL memberFxn ( ); |
Gérer les messages renvoyés : Un exemple de contrôle réutilisable
Cet exemple simple créé un contrôle réutilisable appelé CYellowEdit. Le contrôle fonctionne pareil qu'un contrôle d'édition standard sauf qu'il affiche le texte noir sur un arrière-plan jaune. Il est facile d'ajouter des fonctions membres qui donneraient l'autorisation de commande CYellowEdit à des couleurs d'affichage.
Pour essayer l'exemple qui créé une commande réutilisable
Créer une nouvelle boîte de dialogue dans une application existante. Pour plus d'informations, consultez la rubrique dialog editor.
Vous devez disposer d'une application dans laquelle développer la commande réutilisable. Si vous ne possédez pas d'application existante à utiliser, créez une application basée sur les boîtes de dialogue utilisant AppWizard.
Le projet est chargé dans Visual C++, utilisez ClassWizard pour créer une nouvelle classe appelée CYellowEdit fondée sur CEdit.
Ajoutez les variables composées des trois membres à votre classe CYellowEdit. Les deux premiers sont des variables de COLORREF pour contenir la couleur du texte et de l'arrière-plan. La troisième est un objet CBrush qui contiendra le pinceau pour peindre l'arrière-plan. L'objet CBrush vous permet de créer le pinceau une fois, le référencer simplement après cela, et de détruire le pinceau automatiquement lorsque la commande CYellowEdit est détruite.
Initialisez les variables membres en entrant le constructeur comme suit :
CYellowEdit::CYellowEdit() { m_clrText = RGB( 0, 0, 0 ); m_clrBkgnd = RGB( 255, 255, 0 ); m_brBkgnd.CreateSolidBrush( m_clrBkgnd ); }
En utilisant ClassWizard, ajoutez un gestionnaire du message en miroir WM_CTLCOLOR à votre classe CYellowEdit. Remarquez que le signe égal devant le nom de message dans la liste de messages que vous pouvez gérer indique que le message est mis en miroir. Cela est décrit dans Définir un gestionnaire de messages pour un message en miroir.
ClassWizard ajoute la macro suivante de la table des messages et la fonction squelette pour effectuer les opérations suivantes :
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; }
Remplacez le corops de la fonction par le code suivant. Le code spécifie la couleur du texte, la couleur d'arrière-plan de texte, la couleur d'arrière-plan pour le reste de la commande.
pDC->SetTextColor( m_clrText ); // text pDC->SetBkColor( m_clrBkgnd ); // text bkgnd return m_brBkgnd; // ctl bkgnd
Créez une commande d'édition dans la boîte de dialogue, puis joignez- le à une variable membre en double-cliquant sur le contrôle d'édition tout en conservant une clé d'ordre bas. Dans la boîte de dialogue Ajouter une variable membre, terminez le nom de la variable et sélectionnez « contrôle » pour la catégorie, puis « CYellowEdit » pour le type de variable. N'oubliez pas de définir l'ordre de tabulation dans la boîte de dialogue. En outre, veillez à inclure le fichier d'en-tête pour le contrôle CYellowEdit dans le fichier d'en-tête de la boîte de dialogue.
Générez et exécutez votre application. Le contrôle d'édition aura un arrière-plan jaune.