TN021 : La commande et le routage des messages

Cette note décrit l'architecture de routage et expédition de commande ainsi que des thèmes avancés de routage des messages de fenêtre générale.

Veuillez vous référer au Guide du programmeur Visual C++ pour plus d'informations générales sur les architectures décrites ici, notamment la distinction entre les messages, les notifications de contrôle et les commandes Windows. Cette note suppose que vous êtes très familier avec les problèmes décrits dans la documentation imprimée et traite uniquement des thèmes très avancés.

Fonctionnalité de Dispatch et routage de commandes MFC 1.0 évolue aux MFC 2.0 Architecture

Windows a le message WM_COMMAND est surchargé pour fournir des notifications de commandes de menu, des touches accélérateur et des notifications de la boîte de dialogue contrôle.

MFC 1.0 construit sur qui un peu en permettant à un gestionnaire de commandes (par exemple, "OnFileNew") dans un CWnd classe à appelé en réponse à un particulier WM_COMMANDdérivée. C'est collé avec une structure de données appelée la carte message et aboutit à un mécanisme très efficace à l'espace commande.

MFC 1.0 a également fourni des fonctionnalités supplémentaires pour séparer les notifications de messages de commande de contrôle. Les commandes sont représentés par un ID de 16 bits, parfois appelé un ID de commande. Commandes normalement démarrer à partir d'une classe CFrameWnd (eg: une sélection de menu ou un accélérateur traduit) et avoir mis en déroute à une variété d'autres fenêtres.

MFC 1.0 utilise le routage de commandes dans un sens restreint pour la mise en œuvre d'Interface multidocument (MDI). (Une fenêtre frame MDI délégué de commandes pour la fenêtre enfant MDI active).

Cette fonctionnalité a été généralisée et prolongée dans MFC 2.0 pour permettre à des commandes pour être manipulés par un plus large éventail d'objets (pas seulement les objets window). Il fournit une plus formelle et une architecture extensible pour le routage des messages et réutilise la cible routage de commandes pour gérer non seulement des commandes, mais aussi pour mettre à jour les objets de l'interface utilisateur (comme les éléments de menu et les boutons de barre d'outils) pour tenir compte de la disponibilité actuelle de la commande.

ID de commande

Voir le Guide du programmeur Visual C++ pour obtenir une explication de la commande de routage et de liaison des processus. 20 De Note technique contient des informations sur les ID nom.

Nous utilisons le préfixe générique « ID_ » pour ID de commande. La commande ID sont gt; = 0 x 8000. La barre de statut ou de la ligne de message affiche la chaîne de description de commande s'il existe une ressources STRIN>ABLE avec les mêmes ID : l'ID de commande.

Dans les ressources de votre application, une commande que peut ID apparaît dans plusieurs endroits:

Dans le code source de votre application, une commande que peut ID apparaît dans plusieurs endroits:

Actuellement, la seule mise en oeuvre dans MFC qui requiert l'ID de commande être gt; = 0 x 8000 est la mise en œuvre des boîtes de dialogue et commandes de &GOSUB.

GOSUB commandes, en utilisant l'Architecture de commande de boîtes de dialogue

L'architecture de commande du routage et de permettre aux commandes fonctionne bien avec les fenêtres frames, éléments de menu, boutons de la barre d'outils, boutons de la barre de dialogue, autres barres de contrôles et autres éléments d'interface utilisateur conçues pour mettre à jour sur les commandes de la demande et de la route ou ID de contrôle pour une cible de la commande principale (généralement la fenêtre frame principale). La cible de la commande principale peut router les notifications de contrôle ou de commande à d'autres objets de cible de commande comme il convient.

Une boîte de dialogue (modale ou non modale) peut bénéficier de certaines des caractéristiques de l'architecture de commande si vous affectez l'ID du contrôle de la commande de boîte de dialogue à l'ID de commande appropriée. Soutien pour les boîtes de dialogue n'est pas automatique, vous devez écrire un code supplémentaire.

Notez que pour toutes ces caractéristiques fonctionner correctement, votre ID de commande devrait être gt; = 0 x 8000. Plusieurs boîtes de dialogue pourraient obtenir acheminés vers le même cadre, commandes partagés doivent être > = 0 x 8000, tandis que la non partagé IDC dans une boîte de dialogue spécifique doit être < = 0x7FFF.

Vous pouvez placer un bouton normal dans une boîte de dialogue modale normale avec l'IDC du bouton la valeur de l'ID de commande appropriée. Lorsque l'utilisateur sélectionne le bouton, le propriétaire de la boîte de dialogue (habituellement la fenêtre frame principale) obtient la commande tout comme toute autre commande. Ceci est appelé une commande GOSUB puisqu'il est généralement utilisé pour faire apparaître une autre boîte de dialogue (un GOSUB de la première boîte de dialogue).

Vous pouvez aussi appeler la fonction CWnd::UpdateDialogControls dans votre boîte de dialogue et passer l'adresse de votre fenêtre frame principale. Cette volonté de fonction activé ou désactiver vos contrôles de la boîte de dialogue basée sur s'ils ont des gestionnaires de commande dans le cadre. Cette fonction est appelée automatiquement pour vous, pour les barres de contrôle en boucle au ralenti de votre application, mais vous devez l'appeler directement pour les boîtes de dialogue normales que vous souhaitez avoir cette fonctionnalité.

Lorsque ON_UPDATE_COMMAND_UI est appelée

Maintenir l'état activé/vérifier des éléments de menu du programme tous tout le temps peut être un problème de calculs coûteux. Une technique courante consiste à activer/vérification des éléments de menu uniquement lorsque l'utilisateur sélectionne le POPUP. L'application MFC 2.0 de CFrameWnd gère le message WM_INITMENUPOPUP et utilise l'architecture de routage de commande afin de déterminer les États de menus par le biais de gestionnaires ON_UPDATE_COMMAND_UI.

CFrameWnd gère également le message WM_ENTERIDLE à décrire le menu actuel élément sélectionné sur le statut bar (également connu sous la ligne de message).

Structure de menu d'une application, sous la direction de Visual C++, est utilisée pour représenter les commandes potentielles disponibles au moment de la WM_INITMENUPOPUP . Gestionnaires ON_UPDATE_COMMAND_UI peuvent modifier l'État ou le texte d'un menu, ou pour des utilisations avancées (comme la liste de fichier MRU ou le menu déroulant de verbes OLE), réellement modifier la structure de menu avant que le menu est dessiné.

Le même genre de traitement ON_UPDATE_COMMAND_UI est fait pour les barres d'outils (et autres barres de contrôles) lorsque la demande entame sa boucle inactif. Voir la Référence de bibliothèque de classe et techniques Note 31 pour plus d'informations sur les barres de contrôle.

Imbriqués Popup Menus

Si vous utilisez une structure de menu imbriqué, vous remarquerez que le gestionnaire d'événements ON_UPDATE_COMMAND_UI pour le premier élément de menu dans le menu contextuel est appelé dans deux cas différents.

Tout d'abord, il est appelé pour le popup lui-même. Cela est nécessaire car les menus contextuels n'ont pas d'ID et nous utilisons l'ID du premier élément de menu de la fenêtre contextuelle pour désigner le popup ensemble. Dans ce cas, la variable membre m_pSubMenu de l'objet CCmdUI est non NULL et pointera vers le menu contextuel.

En second lieu, il est appelé juste avant que les éléments de menu dans le menu contextuel sont à tirer. Dans ce cas l'ID désigne simplement le premier élément de menu et la variable de membre m_pSubMenu de l'objet CCmdUI sera NULL.

Cela vous permet d'activer le popup distinct de ses éléments de menu, mais exige que vous écrivez un code au courant du menu. Par exemple, dans un menu imbriqué avec la structure suivante:

Filegt ;
    Nouveau >
        Feuille (ID_NEW_SHEET)
        Graphique (ID_NEW_CHART)

Les commandes ID_NEW_SHEET et ID_NEW_CHART peuvent être activées ou désactivées indépendamment. Le menu contextuel de « Nouveau » doit être activé si ou l'autre des deux est activé.

Le gestionnaire de commandes pour ID_NEW_SHEET (la première commande dans le menu contextuel) pourrait ressembler à:

vOID CMyApp::OnUpdateNewSheet (CCmdUI * pCmdUI)
{
 nbsp ;  Si (pCmdUI - > m_pSubMenu! = NULL)
    {
        / / activer toute popup pour « Nouveau » feuille et graphique
        BOOL bActivez = m_bCanCreateSheet || m_bCanCreateChart ;

/ / CCmdUI::Enable n'est un-op dans ce cas, si nous
        / / doit faire ce qu'il l'aurait fait.
        pCmdUI - > m_pMenu - > EnableMenuItem (pCmdUI - > m_nIndex,
            MF_BYPOSITION | 
                (bActivez ? MF_ENABLED: (MF_DISABLED | MF_GRAYED))) ;
        retour ;
    }
    / / sinon juste la commande de la nouvelle feuille
    pCmdUI - > Enable(m_bCanCreateSheet) ;
}

Le gestionnaire de commandes pour ID_NEW_CHART serait un gestionnaire de commandes de mise à jour normale et le regard quelque chose comme:

vOID CMyApp::OnUpdateNewChart (CCmdUI * pCmdUI)
{
 nbsp ;  pCmdUI - > Enable(m_bCanCreateChart) ;
}

ON_COMMAND et ON_BN_CLICKED

Les macros de carte messages ON_COMMAND et ON_BN_CLICKED sont les mêmes. Le MFC de commandement et contrôle routage mécanisme de notification utilise uniquement l'ID de commande de décider où à la route. Les notifications de contrôle avec le code de notification de contrôle de zéro (BN_CLICKED) sont interprétées comme des commandes.

Note avancé : en fait, tous les messages de notification de contrôle passent par la chaîne de gestionnaire d'événements de commande. Par conséquent, il est techniquement possible pour vous d'écrire un gestionnaire de notification de contrôle pour dire EN_CHANGE dans votre classe de document. Ce n'est pas généralement recommandé étant donné que les applications pratiques de cette fonctionnalité sont peu nombreux, la fonctionnalité n'est pas supportée par ClassWizard et peut entraîner l'utilisation de la fonctionnalité de code fragile.

Désactiver la désactivation automatique des contrôles bouton

Si vous placez un contrôle bouton sur une barre de boîte de dialogue, ou dans une boîte de dialogue à l'aide lorsque vous appelez CWnd::UpdateDialogControls sur votre propre, vous remarquerez que les boutons qui n'ont pas de gestionnaires ON_COMMAND ou ON_UPDATE_COMMAND_UI seront automatiquement désactivés pour vous par le cadre. Dans certains cas vous n'aurez pas à avoir un gestionnaire d'événements, mais vous pouvez rester activé le bouton. La façon la plus facile d'y parvenir est d'ajouter un gestionnaire de commandes factices (facile à faire avec ClassWizard) et ne rien y faire.

Routage des messages de fenêtre

Ce qui suit décrit certains sujets plus avancés sur les classes MFC et leur impact par routage des messages Windows et autres sujets. L'information ici est seulement décrit brièvement. Reportez-vous à la Classe de référence de la bibliothèque pour plus d'informations sur les API publiques. Veuillez consulter le code source des bibliothèques MFC pour plus d'informations sur les détails d'implémentation.

Veuillez consulter Technical Note 17 pour plus de détails sur le nettoyage de la fenêtre, un sujet très important pour tous les CWnd-classes dérivées.

Questions de CWnd

La fonction de membre des implémentation CWnd::OnChildNotify fournit une architecture puissante et extensible pour les fenêtres enfants (également connu sous le nom des témoins) à crochet ou autrement, être informé des messages, des commandes et des notifications de contrôle qui vont à leurs parents (ou le « propriétaire »). Si la fenêtre enfant (et de contrôle) est un objet C++ CWnd elle-même, la fonction virtuelle OnChildNotify est appelée en premier avec les paramètres du message d'origine (c'est-à-dire, une structure MSG ). La fenêtre enfant peut laisser le message, il mange ou modifier le message pour les parents (rare).

La mise en œuvre de CWnd par défaut gère les messages suivants et utilise le crochet de OnChildNotify afin de permettre les fenêtres enfants (contrôles) pour obtenir tout d'abord casser le message:

Vous remarquerez que le crochet de OnChildNotify est utilisé pour modifier des messages owner-draw en self-draw messages.

En plus du crochet OnChildNotify , défilement messages présentent un comportement plus de routage. Veuillez voir ci-dessous pour plus de détails sur les barres de défilement et les sources de messages WM_HSCROLL et WM_VSCROLL.

Questions de CFrameWnd

La classe CFrameWnd fournit la plupart du routage de commandes et interface utilisateur mise à jour de la mise en œuvre. Cela est principalement utilisé pour la fenêtre frame principale de l'application (CWinApp::m_pMainWnd), mais s'applique à toutes les fenêtres du frame.

La fenêtre frame principale est la fenêtre avec la barre de menu et est le parent de la barre d'État ou de la ligne de message. Veuillez vous référer à l'analyse qui précède le routage de commandes et WM_INITMENUPOPUP.

La classe CFrameWnd permet une gestion de l'affichage actif. Les messages suivants sont acheminés par l'intermédiaire de la vue active:

Questions de CMDIFrameWnd/CMDIChildWnd

Les classes de fenêtre frame MDI dérivent de la classe CFrameWnd et donc sont tous deux activés pour le même genre de routage de commandes et interface utilisateur mise à jour fourni dans la classe CFrameWnd. Dans une application MDI typique, seule la fenêtre frame principale (c'est l'objet de CMDIFrameWnd ) tient la barre de menu et la barre d'État et est donc la principale source de l'application de routage de commande.

Le régime général de routage veut que la fenêtre d'enfant MDI active première fissure aux commandes. Fonctions par défaut PreTranslateMessage gérer tables d'accélérateur pour les deux fenêtres enfants MDI (première fois) et le frame MDI (deuxième) ainsi que les accélérateurs de commande du système MDI standards normalement gérés par TranslateMDISysAccel (dernier).

Questions de barre de défilement

Lors de la manipulation de messages de défilement (messages WM_HSCROLLet WM_VSCROLLoufonctions membres OnHScroll /OnVScroll ), vous devriez essayer d'écrire le code de gestionnaire d'événements, donc il ne repose pas sur d'où vient le message de barre de défilement. Ce n'est pas seulement un problème général de Windows, étant donné que les messages de défilement peuvent provenir de vrai défilement barre de contrôles ou de WS_HSCROLL/WS_VSCROLL les barres de défilement qui ne défilement pas barre de contrôles.

MFC s'applique que pour permettre les contrôles de barres de défilement pour enfants ou frères et sœurs de la fenêtre se défiler (en fait, la relation parent/enfant entre la barre de défilement et la fenêtre étant de défilement peut être n'importe quoi). Cela est particulièrement important pour les barres de défilement partagé avec fenêtres. Veuillez vous référer aux techniques Note 29 pour plus de détails sur la mise en œuvre de CSplitterWnd y compris plus d'informations sur les questions de barre de défilement partagé.

Sur une note de côté, il y a deux CWnd où les styles de barre de défilement spécifiés à créent les classes dérivées sont piégés et pas passés à Windows. Quand le passé à une routine de création, WS_HSCROLL et WS_VSCROLL peuvent être définie indépendamment, mais après la création ne peut pas être modifiée. Bien sûr, vous ne devez pas directement tester ou définir le WS_ ?Faites défiler les bits de style de la fenêtre qu'ils ont créés.

De CMDIFrameWnd , les styles de barre de défilement que vous transmettre dans de cas ou de créer sont utilisés pour créer le MDICLIENT. Si vous souhaitez avoir une zone défilante de MDICLIENT (comme les fenêtres gestionnaire de programme) veillez à définir les deux défilement barre de styles (WS_HSCROLL | WS_VSCROLL) pour le style utilisé pour créer le CMDIFrameWnd.

Les styles de barre de défilement s'appliquent aux barres de défilement partagées spéciale pour les régions de séparateur CSplitterWnd . Pour les fenêtres du séparateur statique, vous définirez normalement pas ou style de barre de défilement. Pour fenêtres dynamique, vous aurez généralement la scroll bar style ensemble pour la direction que vous fractionnera, c'est-à-dire WS_HSCROLL si vous pouvez fractionner les lignes, WS_VSCROLL si vous pouvez fractionner des colonnes.

&Notes techniques par le numéro |nbsp ; Notes techniques par catégorie

Index