TN021 : routage de commande et de message
[!REMARQUE]
La note technique suivante n'a pas été modifiée depuis si c'était première inclus dans la documentation en ligne.Par conséquent, certaines procédures et rubriques peuvent être obsolètes ou incorrects.Pour obtenir les informations les plus récentes, il est recommandé que vous trouviez la rubrique d'intérêt dans l'index de la documentation en ligne.
Cette remarque routage décrit de routage des commandes et d'expédition architecture ainsi que message de fenêtre de rubriques avancées en général.
Reportez -vous à Visual C++ pour des informations générales sur les architectures décrites ici, notamment la distinction entre les messages windows, les notifications de contrôle, les commandes et.Cette remarque suppose que vous êtes très familiarisé avec les problèmes décrits dans la documentation et seuls les rubriques avancées imprimés d'adresses très.
Les fonctionnalités MFC 1,0 de routage des commandes et d'expédition évolue à l'architecture MFC 2,0
Les fenêtres a le message de WM_COMMAND qui est surchargé pour donner notifications des commandes de menu, les touches accélérateur et les notifications de contrôle de boîte de dialogue.
MFC 1,0 créé sur celui en permettant à un gestionnaire de commandes (par exemple, « OnFileNew ») dans une classe dérivée de CWnd pour obtenir appeler en réponse à WM_COMMANDspécifique.Cela est collé avec une structure de données appelée la table des messages, et les résultats dans un mécanisme très plus de commande.
Fonctionnalité supplémentaire fournie MFC 1,0 pour séparer les notifications de contrôle des messages de commande.Les commandes sont représentées par un ID 16 bits, parfois appelé un ID de commandeLes commandes normalement démarrent à partir de CFrameWnd (autrement dit, un menu sur ou sur un accélérateur traduit) et sont routées vers diverses autres fenêtres.
Routage des commandes utilisé MFC 1,0 dans un sens limité pour l'implémentation de l'interface multidocument (MDI).(Commandes d'un délégué de fenêtre frame MDI à sa fenêtre MDI enfant active.)
Cette fonctionnalité a été généralisée et étendue dans MFC 2,0 pour autoriser les commandes d'être géré par un éventail d'objets (pas seulement des objets window).Elle fournit une architecture plus formelle et plus extensible pour router les messages et réutilisent le routage de cible de commande pour gérer non seulement les commandes, mais également pour mettre à jour les objets d'interface utilisateur (comme les éléments de menu et des boutons de barre d'outils) pour refléter la disponibilité actuelle d'une commande.
ID de commande
Consultez Visual C++ pour obtenir une explication sur le routage des commandes et du processus de liaison.note technique 20 contient des informations sur l'attribution d'ID.
Nous utilisons le préfixe générique « ID_ » pour les ID de commande.Les ID de commande sont le >= 0x8000.La ligne de message ou la barre d'état affiche la chaîne de description de commandes s'il existe une ressource STRINGTABLE avec les mêmes ID que l'ID de commande
Dans les ressources de votre application, une boîte d'ID de commande apparaît dans plusieurs place :
Dans une ressource STRINGTABLE qui a le même ID que l'invite de ligne de message.
Dans probablement de nombreuses ressources menu qui sont jointes aux éléments de menu qui appellent le même ordre.
(AVANCÉ) dans un bouton de dialogue pour une commande de GOSUB.
Dans le code source de votre application, une boîte d'ID de commande apparaît dans plusieurs place :
Dans votre RESOURCE.H (ou un fichier d'en-tête de symbole principal) pour définir les ID spécifiques à l'application de commande.
PEUT-ÊTRE dans un tableau d'ID utilisée pour créer une barre d'outils.
Dans une macro d' ON_COMMAND .
PEUT-ÊTRE dans une macro d' ON_UPDATE_COMMAND_UI .
Actuellement, la seule implémentation dans MFC qui requiert des identificateurs de commande soit le >= 0x8000 est l'implémentation des boîtes de dialogue/commandes de GOSUB.
Commandes de GOSUB, à l'aide de l'architecture de commande dans les boîtes de dialogue
L'architecture de commande de routage et des commandes de vérifier fonctionne bien avec les fenêtres frame, éléments de menu, boutons de barre d'outils, barre de boîte de dialogue boutons, d'autres barres de contrôles et d'autres éléments d'interface utilisateur conçus pour mettre à jour à la demande et pour router des commandes ou des ID de contrôle à une cible de la commande principale (généralement la fenêtre frame principale).Que la cible de la commande principale peut router les notifications de gérer contrôle ou à d'autres objets de cible de commande appropriés.
Une boîte de dialogue (modale ou non modale) peut tirer parti de certaines fonctionnalités de l'architecture de commande si vous assignez l'ID du contrôle du contrôle de boîte de dialogue à l'identification de commande appropriéeLa prise en charge les dialogues n'est pas automatique, vous pouvez devoir écrire du code supplémentaire.
Notez que pour que toutes ces fonctionnalités fonctionnent correctement, les ID de commande doit être le >= 0x8000.Étant donné que de nombreuses boîtes peuvent obtenir routés vers le même frame, les commandes partagés doivent être le >= 0x8000, alors que les IDC non partagés dans une boîte de dialogue spécifique doivent être le <= 0x7FFF.
Vous pouvez placer un bouton normal dans une boîte de dialogue modale régulière avec IDC de l'ensemble de bouton à l'identification de commande appropriéeLorsque l'utilisateur sélectionne le bouton, le propriétaire de dialogue (généralement la fenêtre frame principale) obtient la commande comme toute autre commande.C'est une commande de GOSUB étant donné qu'il est généralement utilisé pour effectuer un autre dialogue (un GOSUB du premier dialogue).
Vous pouvez également appeler la fonction CWnd::UpdateDialogControls sur votre dialogue et lui passer l'adresse de la fenêtre frame principale.Cette fonction permet ou désactive vos contrôles de boîte de dialogue en fonction s'ils ont les gestionnaires de commandes dans le frame.Cette fonction est appelée automatiquement pour les barres de contrôles dans la boucle inactive de votre application, mais vous devez l'appeler directement pour les boîtes de dialogues normaux dont vous souhaitez effectuer cette fonctionnalité.
Lorsque ON_UPDATE_COMMAND_UI est appelé
Maintenant l'état actif/activé de tous les éléments d'un programme en permanence peuvent représenter un problème gourmand en ressources informatiques.Une technique courante est d'éléments de menu activer/contrôle uniquement lorsque l'utilisateur sélectionne le MESSAGE.L'implémentation MFC 2,0 de CFrameWnd gère le message de WM_INITMENUPOPUP et utilise l'architecture de routage des commandes pour déterminer les rapports des menus via des gestionnaires d' ON_UPDATE_COMMAND_UI .
CFrameWnd gère également le message de WM_ENTERIDLE pour décrire l'élément de menu actuel sélectionné dans la barre d'état (également appelé la ligne de message).
La structure de menu d'une application, modifiée par Visual C++, est utilisé pour représenter les commandes potentielles disponibles au moment de WM_INITMENUPOPUP .Les gestionnaires d'ON_UPDATE_COMMAND_UI peuvent modifier l'état ou le texte d'un menu, ou pour les utilisations avancés (comme la liste des fichiers récents de fichier ou le OLE menu contextuel de verbes), modifier réellement la structure de menu avant que le menu doit être dessiné.
Le même tri de traitement d' ON_UPDATE_COMMAND_UI est fait pour les barres d'outils (et d'autres barres de contrôles) lorsque l'application écrit sa boucle inactive.Consultez la bibliothèque de classes référencer et le note technique 31 pour plus d'informations sur les barres de contrôles.
Menus contextuels imbriqués
Si vous utilisez une structure imbriquée de menu, vous remarquerez que le gestionnaire d' ON_UPDATE_COMMAND_UI pour le premier élément de menu dans le menu contextuel est appelé dans les deux cas individuels.
Tout d'abord, elle est appelée pour le menu contextuel 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 dans le menu contextuel pour nous référence au menu contextuel entier.Dans ce cas, la variable de membre m_pSubMenu de l'objet de CCmdUI sera non null et indiquera le menu contextuel.
Ensuite, il est appelée juste avant que les éléments de menu dans le menu contextuel doivent être dessinés.Dans ce cas, l'ID désigne simplement le premier élément de menu et la variable de membre m_pSubMenu de l'objet de CCmdUI sera NULL.
Cela vous permet d'activer le menu contextuel séparé de ses éléments de menu, mais le requiert que vous écrivez dans un certain menu code fuseaux horaires.Par exemple, dans un menu imbriqué avec la structure suivante :
File>
New>
Sheet (ID_NEW_SHEET)
Chart (ID_NEW_CHART)
Les commandes d'ID_NEW_SHEET et d'ID_NEW_CHART peuvent être indépendamment activées ou désactivées.Le menu contextuel de Nouveau doit être activé si l'un ou l'autre des deux est activé.
Le gestionnaire de commandes pour ID_NEW_SHEET (la première commande dans le menu contextuel) ressemble à celui de :
void CMyApp::OnUpdateNewSheet(CCmdUI* pCmdUI)
{
if (pCmdUI->m_pSubMenu != NULL)
{
// enable entire pop-up for "New" sheet and chart
BOOL bEnable = m_bCanCreateSheet || m_bCanCreateChart;
// CCmdUI::Enable is a no-op for this case, so we
// must do what it would have done.
pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex,
MF_BYPOSITION |
(bEnable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
return;
}
// otherwise just the New Sheet command
pCmdUI->Enable(m_bCanCreateSheet);
}
Le gestionnaire de commandes pour ID_NEW_CHART serait un gestionnaire de commandes et une apparence normales de mise à jour des éléments semblables :
void CMyApp::OnUpdateNewChart(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_bCanCreateChart);
}
ON_COMMAND et ON_BN_CLICKED
Les macros de table des messages pour ON_COMMAND et ON_BN_CLICKED sont identiques.Le mécanisme de routage de notification de gérer et de contrôle MFC utilise uniquement l'ID de commande pour déterminer où le routage à.Les notifications de contrôle au code de notification de contrôle de zéro (BN_CLICKED) sont interprétées comme commandes.
[!REMARQUE]
En fait, tous les messages de notification de contrôle sont concernées par la chaîne du gestionnaire de commandes.Par exemple, il est techniquement possible que vous entriez un gestionnaire de notification de contrôle pour EN_CHANGE dans votre classe de document.Ce n'est généralement pas recommandé car les applications pratiques de ces fonctionnalités sont peu, la fonctionnalité n'est pas pris en charge par l'assistant classe, et l'utilisation de la fonctionnalité peut générer du code fragile.
Désactiver désactiver automatique des contrôles bouton
Si vous placez un contrôle bouton d'une barre de boîte de dialogue, ou dans un à l'aide de dialogue où vous appelez CWnd::UpdateDialogControls vous-même, vous remarquerez que des boutons qui n'ont pas de gestionnaires d' ON_COMMAND ou d' ON_UPDATE_COMMAND_UI seront automatiquement désactivés pour vous par l'infrastructure.Dans certains cas, vous n'aurez pas besoin d'avoir un gestionnaire, mais vous souhaiterez le bouton pour rester actif.La façon la plus simple pour ce faire consiste à ajouter un gestionnaire de commandes fictive (aident à l'assistant classe) et de ne rien dans celui-ci.
Routage des messages de fenêtre
Les éléments suivants décrivent encore plus de rubriques avancées sur les classes MFC et comment le routage des messages windows et d'autres rubriques les exécutent.Les informations dans ce cas sont uniquement brièvement décrites.Reportez -vous à la référence de la bibliothèque de classes pour plus d'informations sur les API publiques. Reportez -vous au code source de la bibliothèque MFC pour plus d'informations sur les détails d'implémentation.
Reportez -vous à note technique 17 pour plus d'informations sur le nettoyage de fenêtre, un sujet très important pour tout le CWndclasses dérivées.
Problèmes de CWnd
La fonction membre CWnd::OnChildNotify d'implémentation fournit une architecture puissante et extensible pour les fenêtres enfants (également appelés contrôles) de se connecter ou sinon soit informée des messages, les commandes, et les notifications de contrôle qui vont à leur parent (ou « propriétaire).Si la fenêtre enfant (/control) est un objet C++ CWnd lui-même, la fonction virtuelle OnChildNotify est d'abord appelée avec les paramètres du premier message (autrement dit, une structure de MSG ).La fenêtre enfant peut laisser le message seul, le manger, ou modifier le message du parent (rare).
L'implémentation de CWnd par défaut traite les messages suivants et utilise le raccordement de OnChildNotify pour autoriser les fenêtres enfants (contrôles) au premier accès au message :
WM_MEASUREITEM et WM_DRAWITEM (pour le dessin automatique)
WM_COMPAREITEM et WM_DELETEITEM (pour le dessin automatique)
WM_HSCROLL et WM_VSCROLL
WM_CTLCOLOR
WM_PARENTNOTIFY
Vous remarquerez le raccordement de OnChildNotify est utilisé pour modifier les messages owner-draw dans des messages de dessin automatique.
En plus de le raccordement d' OnChildNotify , les messages de défilement ont plus de comportement de routage. Consultez ci-dessous pour plus de détails sur les barres de défilement et les sources de messages de WM_HSCROLL et de WM_VSCROLL .
Problèmes de CFrameWnd
La classe de CFrameWnd fournit la plupart du routage des commandes et de l'interface utilisateur et met à jour l'implémentation.Cela est essentiellement utilisé pour la fenêtre frame principale de l'application (CWinApp::m_pMainWnd) et applique à toutes les fenêtres frame.
La fenêtre frame principale est la fenêtre avec la barre de menus et est le parent de la barre d'état ou de la ligne de message. Consultez la discussion ci-dessus sur le routage des commandes et le WM_INITMENUPOPUP.
La classe de CFrameWnd assure la gestion de la vue active.Les messages suivants sont routées via la vue active :
Tous les messages de commande (la vue active obtient le premier accès à eux).
Messages deWM_HSCROLL et de WM_VSCROLL des barres de défilement frère (voir ci-dessous).
L'option d'obtention deWM_ACTIVATE (et WM_MDIACTIVATE pour MDI) s'est transformé en appels à la fonction virtuelle CView::OnActivateView.
Problèmes de CMDIFrameWnd/CMDIChildWnd
Les deux classes de fenêtre frame MDI dérivent de CFrameWnd et par conséquent sont activées pour le même tri du routage des commandes et de mettre à jour de l'interface utilisateur fournis dans CFrameWnd.Dans une application type MDI, seule la fenêtre frame principale (autrement dit, l'objet de CMDIFrameWnd ) maintient la barre de menus et la barre d'état et est par conséquent la source des clés d'implémentation de routage des commandes.
La modèle général de routage est que la fenêtre enfant MDI active obtient le premier accès aux commandes.Les tables d'accélérateurs de handle de fonctions de PreTranslateMessage par défaut pour les fenêtres enfants MDI (premier) et le frame MDI (second) ainsi que les accélérateurs standard de système-commande MDI normalement managés par TranslateMDISysAccel (dernier).
Problèmes de barre de défilement
En gérant le défilement-message (WM_HSCROLL/OnHScroll et/ou WM_VSCROLL/OnVScroll), vous devez essayer d'écrire le code du gestionnaire et ne repose pas sur l'emplacement à partir duquel le message de barre de défilement a eu lieu.Il s'agit pas uniquement un problème général windows, car ces messages de défilement peuvent provenir de véritables contrôles de barre de défilement ou des barres de défilement de WS_HSCROLL/WS_VSCROLL qui ne sont pas des contrôles de barre de défilement.
MFC étend place pour autoriser les contrôles de barre de défilement soient enfant ou frères de la fenêtre qui est effectuée par défilement (en fait, la relation entre la barre de défilement et fenêtre parent/enfant ne soit effectuée défiler peuvent être quelconque).C'est particulièrement important pour les barres de défilement partagés avec les fenêtres fractionnées. Reportez -vous à note technique 29 pour plus d'informations sur l'implémentation de CSplitterWnd notamment plus d'informations sur les questions partagées de barre de défilement.
Sur une note marginal, il existe deux classes dérivées de CWnd où les styles de barre de défilement spécifiés à l'heure de création sont interceptés et pas passés à windows.Lorsqu'elles sont passées à une routine de création, WS_HSCROLL et WS_VSCROLL peuvent être définis de manière indépendante, mais après la création ne peut pas être modifiée.Bien sûr, vous ne devez pas tester directement ou définir le WS_ ? MAKE DÉFILER les bits de style de la fenêtre qu'elle a créée.
Pour CMDIFrameWnd les styles de barre de défilement que vous passez à Créer ou LoadFrame sont utilisés pour créer le MDICLIENT.Si vous souhaitez avoir une zone déroulante de MDICLIENT (comme le gestionnaire de programme Windows) veillez à définir les deux styles de barre de défilement (WS_HSCROLL | WS_VSCROLL) pour le style utilisé pour créer CMDIFrameWnd.
Pour CSplitterWnd les styles de barre de défilement appliquent aux barres de défilement partagées spéciales pour les zones de séparateur.Pour les fenêtres fractionnées statiques, vous ne définirez normalement pas l'un ou l'autre de style de barre de défilement.Pour les fenêtres fractionnées dynamiques, vous aurez généralement le style de barre de défilement défini pour la direction que vous fractionnerez, c. autrement dit., WS_HSCROLL si vous pouvez fractionner des lignes, WS_VSCROLL si vous pouvez fractionner des colonnes.