TN062 : réflexion de message pour les contrôles Windows
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 décrit la réflexion des messages, une nouvelle fonctionnalité dans MFC 4.0. Il contient également des instructions pour créer un contrôle réutilisable simple qui utilise la réflexion des messages.
Cette note technique ne traite pas de la réflexion des messages, car elle s’applique aux contrôles ActiveX (anciennement appelés contrôles OLE). Consultez l’article Contrôles ActiveX : sous-classe d’un contrôle Windows.
Qu’est-ce que le message Réflexions ion
Windows contrôle fréquemment l’envoi de messages de notification à leurs fenêtres parentes. Par exemple, de nombreux contrôles envoient un message de notification de couleur de contrôle (WM_CTLCOLOR ou une de ses variantes) à leur parent pour permettre au parent de fournir un pinceau pour peindre l’arrière-plan du contrôle.
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 ces messages. Cela signifie que le code de gestion du message doit se trouver dans la classe de la fenêtre parente et qu’il doit être dupliqué dans chaque classe qui doit gérer ce message. Dans le cas ci-dessus, chaque boîte de dialogue qui voulait des contrôles avec des arrière-plans personnalisés doit gérer le message de notification de couleur de contrôle. Il serait beaucoup plus facile de réutiliser du code si une classe de contrôle pourrait être écrite 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 gérer les messages de notification. En outre, MFC 4.0 facilite la réutilisation en fournissant une fonctionnalité appelée « réflexion des messages » qui permet à ces messages de notification d’être gérés dans la fenêtre de contrôle enfant ou dans la fenêtre parente, ou dans les deux. Dans l’exemple de couleur d’arrière-plan du contrôle, vous pouvez maintenant écrire une classe de contrôle qui définit sa propre couleur d’arrière-plan en gérant le message WM_CTLCOLOR réfléchi , sans compter sur le parent. (Notez que, étant donné que la réflexion de message est implémentée par MFC, et non par Windows, la classe de fenêtre parente doit être dérivée de CWnd
la réflexion du message pour fonctionner.)
Les versions antérieures de MFC ont fait quelque chose de similaire à la réflexion des messages en fournissant des fonctions virtuelles pour quelques messages, tels que des messages pour les zones de liste dessinées par le propriétaire (WM_DRAWITEM, etc.). Le nouveau mécanisme de réflexion des messages est généralisé et cohérent.
La réflexion des messages est compatible avec le code écrit pour les versions de MFC antérieures à la version 4.0.
Si vous avez fourni un gestionnaire pour un message spécifique ou pour une plage de messages, dans la classe de votre fenêtre parente, il remplace les gestionnaires de messages répercutés pour le même message fourni que vous n’appelez pas la fonction de gestionnaire de classe de base dans votre propre gestionnaire. Par exemple, si vous gérez WM_CTLCOLOR dans votre classe de boîte de dialogue, votre gestion remplace les gestionnaires de messages répercutés.
Si, dans votre classe de fenêtre parente, vous fournissez un gestionnaire pour un message WM_NOTIFY spécifique ou une plage de messages WM_NOTIFY, votre gestionnaire est appelé uniquement si le contrôle enfant envoyant ces messages n’a pas de gestionnaire de messages répercuté via ON_NOTIFY_REFLECT()
. Si vous utilisez ON_NOTIFY_REFLECT_EX()
dans votre carte de messages, votre gestionnaire de messages peut ou ne pas autoriser la fenêtre parente à gérer le message. Si le gestionnaire retourne false, le message est également géré par le parent, tandis qu’un appel qui retourne TRUE n’autorise pas le parent à le gérer. Notez que le message réfléchi est géré avant le message de notification.
Lorsqu’un message WM_NOTIFY est envoyé, le contrôle est offert la première chance de le gérer. Si un autre message réfléchi est envoyé, la fenêtre parente a la première chance de la gérer et le contrôle reçoit le message répercuté. Pour ce faire, il aura besoin d’une fonction de gestionnaire et d’une entrée appropriée dans la carte des messages de classe du contrôle.
La macro de mappage de messages pour les messages réfléchis est légèrement différente de celle des notifications régulières : elle a _REFLECT ajoutée à son nom habituel. Par exemple, pour gérer un message WM_NOTIFY dans le parent, vous utilisez la macro ON_NOTIFY dans la carte de messages du parent. Pour gérer le message réfléchi dans le contrôle enfant, utilisez la macro ON_NOTIFY_REFLECT dans la carte des messages du contrôle enfant. Dans certains cas, les paramètres sont également différents. Notez que ClassWizard peut généralement ajouter les entrées de mappage de messages pour vous et fournir des implémentations de fonction squelette avec des paramètres corrects.
Consultez TN061 : ON_NOTIFY et WM_NOTIFY Messages pour plus d’informations sur le nouveau message WM_NOTIFY.
Prototypes de fonctions de mappage de messages et de gestionnaire pour les messages Réflexions ed
Pour gérer un message de notification de contrôle répercuté, utilisez les macros de carte de messages et les prototypes de fonction répertoriés dans le tableau ci-dessous.
ClassWizard peut généralement ajouter ces entrées de mappage de messages pour vous et fournir des implémentations de fonction squelette. Consultez Définition d’un gestionnaire de messages pour un message Réflexions ed Pour plus d’informations sur la façon de définir des gestionnaires pour les messages réfléchis.
Pour convertir le nom du message en nom de macro réfléchi, ajoutez ON_ et ajoutez _REFLECT. Par exemple, WM_CTLCOLOR devient ON_WM_CTLCOLOR_REFLECT. (Pour voir quels messages peuvent être reflétés, effectuez la conversion opposée sur les entrées de macro dans le tableau ci-dessous.)
Les trois exceptions à la règle ci-dessus sont les suivantes :
La macro pour les notifications WM_COMMAND est ON_CONTROL_REFLECT.
La macro pour les réflexions WM_NOTIFY est ON_NOTIFY_REFLECT.
La macro pour les réflexions ON_UPDATE_COMMAND_UI est ON_UPDATE_COMMAND_UI_REFLECT.
Dans chacun des cas spéciaux ci-dessus, vous devez spécifier le nom de la fonction membre du gestionnaire. Dans les autres cas, vous devez utiliser le nom standard de votre fonction de gestionnaire.
Les significations des paramètres et des valeurs de retour des fonctions sont documentées sous le nom de la fonction ou le nom de la fonction avec On précédé. Par exemple, CtlColor
est documenté dans OnCtlColor
. Plusieurs gestionnaires de messages réfléchis ont besoin de moins de paramètres que les gestionnaires similaires dans une fenêtre parente. Il suffit de faire correspondre les noms dans le tableau ci-dessous avec les noms des paramètres formels de la documentation.
Entrée de carte | Prototype de fonction |
---|---|
ON_CONTROL_REFLECT(wNotifyCode ,)memberFxn |
afx_msg voidmemberFxn ( ) ; |
ON_NOTIFY_REFLECT(wNotifyCode ,)memberFxn |
afx_msg voidmemberFxn ( NMHDRpNotifyStruct *, résultat 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 |
Les macros ON_NOTIFY_REFLECT et ON_CONTROL_REFLECT ont des variantes qui permettent à plusieurs objets (tels que le contrôle et son parent) de gérer un message donné.
Entrée de carte | Prototype de fonction |
---|---|
ON_NOTIFY_REFLECT_EX(wNotifyCode ,)memberFxn |
afx_msg BOOLmemberFxn ( NMHDRpNotifyStruct *, résultat LRESULT) ;* |
ON_CONTROL_REFLECT_EX(wNotifyCode ,)memberFxn |
afx_msg BOOLmemberFxn ( ) ; |
Gestion des messages Réflexions ed : exemple de contrôle réutilisable
Cet exemple simple crée un contrôle réutilisable appelé CYellowEdit
. Le contrôle fonctionne de la même façon qu’un contrôle d’édition standard, sauf qu’il affiche du texte noir sur un arrière-plan jaune. Il serait facile d’ajouter des fonctions membres qui permettent au CYellowEdit
contrôle d’afficher différentes couleurs.
Pour essayer l’exemple qui crée un contrôle réutilisable
Créez une boîte de dialogue dans une application existante. Pour plus d’informations, consultez la rubrique de l’éditeur de boîte de dialogue.
Vous devez disposer d’une application dans laquelle développer le contrôle réutilisable. Si vous n’avez pas d’application existante à utiliser, créez une application basée sur une boîte de dialogue à l’aide d’AppWizard.
Avec votre projet chargé dans Visual C++, utilisez ClassWizard pour créer une classe appelée
CYellowEdit
en fonctionCEdit
de .Ajoutez trois variables membres à votre
CYellowEdit
classe. Les deux premières seront des variables COLORREF pour contenir la couleur du texte et la couleur d’arrière-plan. Le troisième sera unCBrush
objet qui contiendra le pinceau pour peindre l’arrière-plan. L’objetCBrush
vous permet de créer le pinceau une fois, en le référençant simplement après cela, et de détruire automatiquement le pinceau lorsque leCYellowEdit
contrôle est détruit.Initialisez les variables membres en écrivant le constructeur comme suit :
CYellowEdit::CYellowEdit() { m_clrText = RGB(0, 0, 0); m_clrBkgnd = RGB(255, 255, 0); m_brBkgnd.CreateSolidBrush(m_clrBkgnd); }
À l’aide de ClassWizard, ajoutez un gestionnaire pour le message WM_CTLCOLOR réfléchi à votre
CYellowEdit
classe. Notez que la connexion égale devant le nom du message dans la liste des messages que vous pouvez gérer indique que le message est reflété. Cette procédure est décrite dans Définition d’un gestionnaire de messages pour un message Réflexions ed Message.ClassWizard ajoute la macro de carte de messages et la fonction squelette suivantes pour vous :
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 corps de la fonction par le code suivant. Le code spécifie la couleur de texte, la couleur d’arrière-plan du texte et la couleur d’arrière-plan pour le reste du contrôle.
pDC->SetTextColor(m_clrText); // text pDC->SetBkColor(m_clrBkgnd); // text bkgnd return m_brBkgnd; // ctl bkgnd
Créez un contrôle d’édition dans votre boîte de dialogue, puis attachez-le à une variable membre en double-cliquant sur le contrôle d’édition tout en maintenant une clé de contrôle enfoncée. Dans la boîte de dialogue Ajouter une variable membre, terminez le nom de la variable et choisissez « 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. Veillez également à inclure le fichier d’en-tête du contrôle dans le
CYellowEdit
fichier d’en-tête de votre boîte de dialogue.Créez et exécutez votre application. Le contrôle d’édition aura un arrière-plan jaune.