Guide pratique pour créer une barre de menus Internet Explorer-Style

À première vue, la barre de menus de Microsoft Internet Explorer 5 et versions ultérieures ressemble à un menu standard. Toutefois, il semble très différent lorsque vous commencez à l’utiliser.

La capture d’écran suivante montre la barre de menus Windows Internet Explorer avec le menu Outils sélectionné.

capture d’écran montrant la barre de menus windows Internet Explorer, avec le menu Outils sélectionné

La barre de menus est en fait un contrôle de barre d’outils qui ressemble à un menu standard. Au lieu d’éléments de menu de niveau supérieur, une barre de menus comporte une série de boutons de texte uniquement qui affichent un menu déroulant lorsque vous cliquez dessus. Toutefois, en tant que type spécialisé de barre d’outils, une barre de menus a certaines fonctionnalités qui manquent aux menus standard :

  • Il peut être personnalisé à l’aide de techniques de barre d’outils standard, ce qui permet à l’utilisateur de déplacer, de supprimer ou d’ajouter des éléments.
  • Il peut avoir un suivi à chaud, afin que les utilisateurs sachent quand ils sont au-dessus d’un élément de niveau supérieur sans avoir à cliquer dessus d’abord.

Une barre de menus peut être incorporée dans un contrôle de barre d’outils, ce qui lui donne les fonctionnalités suivantes :

  • Il peut avoir une pince, qui permet à l’utilisateur de déplacer ou de redimensionner la bande.
  • Il peut partager une bande dans le contrôle de barre d’barres avec d’autres bandes, telles que la barre d’outils standard dans l’illustration précédente.
  • Il peut afficher un chevron lorsqu’il est couvert par une bande adjacente, ce qui permet à l’utilisateur d’accéder aux éléments masqués.
  • Il peut avoir une bitmap d’arrière-plan définie par l’application.

Cette rubrique explique comment implémenter une barre de menus. Étant donné qu’une barre de menus est une implémentation spécialisée d’un contrôle de barre d’outils, l’accent sera mis sur les rubriques spécifiques aux barres de menus. Pour plus d’informations sur l’incorporation d’une barre d’outils dans un contrôle de barre d’outils, voir How to Create an Internet Explorer-Style Toolbar et About Rebar Controls.

Création d’une barre d’outils dans une barre de menus

Pour transformer une barre d’outils en barre de menus :

  • Créez une barre d’outils plate en incluant TBSTYLE_FLAT avec les autres indicateurs de style de fenêtre. Le style TBSTYLE_FLAT permet également le suivi à chaud. Avec ce style, la barre de menus ressemble beaucoup à un menu standard jusqu’à ce que l’utilisateur active un bouton. Ensuite, le bouton semble se détacher de la barre d’outils et appuyer lorsqu’il est cliqué, comme un bouton standard. Étant donné que le suivi à chaud est activé, il suffit d’activer un bouton pour que le curseur pointe sur celui-ci. Si le curseur se déplace vers un autre bouton, il est activé et l’ancien bouton désactivé.
  • Créez des boutons de style liste en incluant TBSTYLE_LIST avec les autres indicateurs de style de fenêtre. Ce style crée un bouton plus mince qui ressemble davantage à un élément de menu de niveau supérieur standard.
  • Définissez les boutons avec du texte uniquement en définissant le membre iBitmap de la structure TBBUTTON du bouton sur I_IMAGENONE et le membre iString sur le texte du bouton.
  • Donnez à chaque bouton le style BTNS_DROPDOWN . Lorsque vous cliquez sur le bouton, le contrôle de barre d’outils envoie à votre application une notification TBN_DROPDOWN pour l’inviter à afficher le menu du bouton.
  • Incorporez la barre de menus dans une bande de barres d’armature. Activez les pinces et les chevrons, comme indiqué dans La barre d’outils Création d’un Explorer-Style Internet.
  • Implémentez un gestionnaire de TBN_DROPDOWN pour afficher le menu déroulant du bouton lorsque vous cliquez dessus. Le menu déroulant est un type de menu contextuel. Il est créé à l’aide de la fonction TrackPopupMenu , avec son coin supérieur gauche aligné sur le coin inférieur gauche du bouton.
  • Implémentez la navigation au clavier afin que la barre de menus soit entièrement accessible sans souris.
  • Implémenter le suivi à chaud du menu. Avec les menus standard, une fois le menu d’un élément de menu de niveau supérieur affiché, le déplacement du curseur sur un autre élément de niveau supérieur affiche automatiquement son menu et réduit le menu de l’élément précédent. Le contrôle de barre d’outils effectue le suivi à chaud du curseur et modifie l’image du bouton, mais il affiche automatiquement le nouveau menu. Votre application doit le faire explicitement.

La plupart de ces éléments sont simples à implémenter et sont abordés ailleurs. Consultez Comment créer une barre d’outils Internet Explorer-Style, À propos des contrôles de barre d’outils ou À propos des contrôles de barre d’outils pour obtenir une présentation générale de l’utilisation des barres d’outils et des contrôles d’armature. Pour plus d’informations sur la gestion des menus contextuels, consultez Menus . Les deux derniers éléments, la navigation au clavier et le suivi à chaud des menus, sont abordés dans le reste de cette rubrique.

Gestion de la navigation avec menu Hot-Tracking désactivé

Les utilisateurs peuvent choisir de naviguer dans la barre de menus avec la souris, le clavier ou un mélange des deux. Pour implémenter la navigation dans la barre de menus, votre application doit gérer les notifications de barre d’outils et surveiller la souris et le clavier. Cette tâche peut être divisée en deux parties distinctes : avec et sans suivi à chaud de menu. Cette section explique comment gérer la navigation lorsqu’aucun menu n’est affiché et que le suivi à chaud des menus n’est pas activé.

Si le suivi à chaud des menus est désactivé, vous pouvez traiter une barre de menus comme une barre d’outils normale. Si l’utilisateur navigue avec une souris, il suffit que votre application gère la notification TBN_DROPDOWN . Lorsque cette notification est reçue, affichez le menu déroulant approprié et activez le suivi à chaud du menu. À partir de là, vous êtes dans le régime de suivi à chaud du menu décrit dans Gestion de la navigation avec menu Hot-Tracking Activé.

Comme indiqué dans Navigation mixte, vous devez également gérer la notification TBN_HOTITEMCHANGE pour suivre le bouton actif. Cette notification n’est pas pertinente si l’utilisateur navigue uniquement avec la souris, mais elle est nécessaire lorsque la navigation entre la souris et le clavier est mixte.

Comme indiqué dans la section précédente, l’utilisateur peut effectuer un certain nombre d’opérations de navigation avec le clavier lorsque le suivi à chaud du menu est désactivé. Les contrôles de barre d’outils prennent en charge la navigation au clavier uniquement s’ils ont le focus. Ils ne gèrent pas non plus tous les appuis sur les touches nécessaires pour les barres de menus. La solution la plus simple pour gérer la navigation au clavier consiste à traiter explicitement les événements d’appui sur les touches pertinentes.

Si le suivi à chaud des menus est désactivé, votre application doit gérer ces événements d’appui sur les touches de la manière suivante :

  • Touche F10. Activez le premier bouton avec TB_SETHOTITEM.
  • Touches flèche gauche et flèche droite. Activez le bouton adjacent avec TB_SETHOTITEM. Si l’utilisateur tente de naviguer à l’autre extrémité de la barre de menus, activez le premier bouton à l’extrémité opposée.
  • Clé ESCAPE. Désactivez le bouton actif avec TB_SETHOTITEM. La barre de menus doit être retournée à l’état qu’elle avait avant l’activation du premier bouton.
  • Touche d’accélérateur Alt-Key . Utilisez le message TB_MAPACCELERATOR pour déterminer à quel bouton correspond le caractère clé . Affichez le menu déroulant du bouton et activez le suivi à chaud du menu.
  • Touche Bas. Si un bouton est actif mais qu’aucun menu n’a été affiché, affichez le menu du bouton et activez le suivi à chaud du menu.
  • Touche Entrée. Désactivez le bouton actif avec TB_SETHOTITEM. La barre de menus doit être retournée à l’état qu’elle avait avant l’activation du premier bouton.

Les gestionnaires de navigation au clavier décrits dans la section précédente effectuent essentiellement deux tâches : effectuer le suivi du bouton actif et afficher le menu approprié lorsqu’un bouton est sélectionné. Ces gestionnaires sont suffisants tant que l’utilisateur navigue uniquement avec le clavier. Toutefois, les utilisateurs mélangent souvent la navigation au clavier et à la souris. Par exemple, ils peuvent activer le premier bouton avec la touche F10, utiliser la souris pour activer un autre bouton, puis ouvrir son menu avec la flèche bas. Si vous surveillez uniquement les appuis sur la touche pour suivre la touche active, vous allez afficher le menu incorrect. Vous devez également gérer la notification TBN_HOTITEMCHANGE pour effectuer un suivi précis du bouton actif.

Gestion de la navigation avec Hot-Tracking de menu activé

Lorsque le suivi à chaud du menu est activé, votre application doit modifier la façon dont elle répond à la navigation de l’utilisateur. Pour répliquer le comportement des menus standard, vous devez implémenter explicitement les fonctionnalités suivantes.

Avec la navigation de la souris :

  • Si l’utilisateur déplace le curseur sur un autre bouton, ce menu s’affiche immédiatement et le menu précédent disparaît.
  • Le suivi à chaud du menu reste actif jusqu’à ce que l’utilisateur sélectionne une commande ou clique sur un point qui ne fait pas partie de la région de menu. L’une ou l’autre action désactive le suivi à chaud du menu jusqu’à ce qu’un autre bouton soit cliqué.
  • Si le curseur quitte le menu, le menu déroulant actuel reste jusqu’à ce que le curseur revienne sur ou que l’utilisateur clique sur un point à l’extérieur de la zone couverte par le menu. Si le curseur revient à un autre bouton que celui actuellement affiché, l’ancien menu est réduit et le nouveau s’affiche.

Avec la navigation au clavier :

  • La touche FLÈCHE DROITE déplace le focus vers la droite. Si l’élément a un sous-menu, affichez le sous-menu. Si l’élément n’a pas de sous-menu, réduisez le menu et les sous-menus, activez le bouton suivant avec TB_SETHOTITEM et affichez le menu correspondant au bouton adjacent. Si le dernier bouton est actif lors de la réception de ce message, affichez le menu correspondant au premier bouton.

  • La touche FLÈCHE GAUCHE déplace le focus vers la gauche. Si l’élément est un sous-menu, réduisez-le et déplacez le focus sur son menu parent. Si l’élément n’est pas un sous-menu, réduisez le menu, activez le bouton suivant avec TB_SETHOTITEM et affichez le menu correspondant.

  • La touche ESCAPE sauvegarde l’affichage d’une étape.

    • Si un sous-menu s’affiche, il est réduit et le focus est déplacé vers le menu parent.
    • Si le menu d’un bouton s’affiche, il est réduit et le suivi à chaud du menu est désactivé. Le bouton de l’élément reste actif.
    • Si aucun menu n’est affiché, mais qu’un bouton est actif, le bouton est désactivé et le suivi à chaud du menu est désactivé.
  • Les touches flèche haut et bas sont utilisées uniquement pour naviguer dans un menu particulier.

  • La touche ENTRÉE lance la commande associée à un élément de menu. Si l’élément de menu a un sous-menu, la touche ENTRÉE l’affiche.

Comme avec le cas de désactivation du suivi à chaud du menu, votre application doit être en mesure de gérer la souris, le clavier et la navigation mixte. Toutefois, le fait qu’un menu s’affiche signifie que la messagerie doit être gérée différemment.

Traitement des messages pour les Hot-Tracking de menu

Le suivi à chaud des menus nécessite qu’un menu soit affiché à tout moment, à l’exception du bref intervalle nécessaire pour basculer vers un nouveau menu. Toutefois, le menu déroulant affiché par TrackPopupMenu est modal. Votre application continuera à recevoir des messages directement, notamment des messages WM_COMMAND, TBN_HOTITEMCHANGE et des messages de menu normaux tels que WM_MENUSELECT. Toutefois, il ne recevra pas directement les messages clavier ou souris de bas niveau. Pour gérer des messages tels que WM_MOUSEMOVE, vous devez définir un hook de message pour intercepter les messages qui sont dirigés vers le menu.

Lorsqu’un menu déroulant s’affiche, définissez le hook de message en appelant la fonction SetWindowsHookEx avec le paramètre idHook défini sur WH_MSGFILTER. Tous les messages destinés au menu seront passés à votre MessageProc. Par exemple, le fragment de code suivant définit un hook de message qui intercepte les messages qui vont dans un menu déroulant. MsgHook est le nom de la procédure de raccordement et hhookMsg est le handle de la procédure.

hhookMsg = SetWindowsHookEx(WH_MSGFILTER, MsgHook, HINST_THISDLL, 0);

Les messages de menu sont identifiés en définissant le paramètre nCode de la procédure de raccordement sur MSGF_MENU. Le paramètre lParam pointe vers une structure MSG avec le message. Les détails des messages qui doivent être gérés et comment sont abordés dans le reste de cette rubrique.

Votre application doit passer tous les messages au hook de message suivant en appelant la fonction CallNextHookEx . Vous devez également envoyer des messages de souris directement au contrôle de barre d’outils, en veillant à convertir toutes les coordonnées de point en espace de coordonnées client de la barre d’outils. L’envoi direct des messages garantit que le contrôle de barre d’outils reçoit les messages de souris appropriés. Pour instance, la barre d’outils doit recevoir des messages WM_MOUSEMOVE afin de suivre à chaud ses boutons.

Lorsqu’un nouveau bouton est activé, votre application doit réduire l’ancien menu déroulant avec un message WM_CANCELMODE et afficher un nouveau menu. Il doit également réduire le menu déroulant lorsque le focus est effectué à partir de la barre de menus avec la navigation au clavier ou en cliquant à l’extérieur de la zone de menu. Chaque fois que vous réduisez un menu, vous devez libérer son hook de message à l’aide de la fonction UnhookWindowsHookEx . Si vous devez afficher un autre menu déroulant, créez un crochet de message. Lorsqu’une commande est lancée, le menu est automatiquement réduit, mais vous devez explicitement libérer le hook de message.

L’exemple de code suivant libère le hook de message qui a été défini dans l’exemple précédent.

UnhookWindowsHookEx(hhookMsg);

Lorsqu’un contrôle de barre d’outils normal suit les boutons à chaud, il met en surbrillance le bouton actif et envoie à l’application une notification TBN_HOTITEMCHANGE chaque fois qu’un nouveau bouton est activé. Votre application est chargée d’afficher le menu déroulant approprié. Elle doit :

  • Gérez la notification TBN_HOTITEMCHANGE pour effectuer le suivi du bouton actif. Lorsque le bouton actif change, réduisez l’ancien menu et créez-en un nouveau.
  • Gérez la notification TBN_DROPDOWN qui est envoyée lorsqu’un clic sur un bouton est cliqué. Il doit ensuite réduire le menu et désactiver le suivi à chaud du menu. Le bouton reste actif.
  • Gérez les messages WM_LBUTTONDOWN, WM_RBUTTONDOWN et WM_MOUSEMOVE dans votre procédure de raccordement de message pour effectuer le suivi de la position de la souris. Si vous cliquez sur la souris en dehors de la zone de menu, réduisez le menu déroulant actuel, désactivez le suivi à chaud du menu et revenez à l’état de préactivation de la barre de menus.
  • Lorsqu’une commande de menu est lancée, désactivez le suivi à chaud des menus. Le menu sera automatiquement réduit, mais vous devez explicitement libérer le crochet de message.

Vous devez également gérer la messagerie liée au menu, telle que le message WM_INITMENUPOPUP envoyé lorsqu’un élément de menu doit afficher un sous-menu. Pour plus d’informations sur la façon de gérer ces messages, consultez Menus.

Votre application doit traiter les messages clavier dans la procédure de raccordement de message et agir sur ceux qui affectent le suivi à chaud des menus. Les pressions sur les touches suivantes doivent être gérées :

  • Clé D’échappement. La touche ESCAPE sauvegarde l’affichage d’un niveau. Si un sous-menu est affiché, il doit être réduit. Si le menu principal d’un bouton s’affiche, réduisez-le et désactivez le suivi à chaud du menu. Le bouton reste actif.
  • Touche Droite. Si l’élément a un sous-menu, affichez-le. Si l’élément n’a pas de sous-menu, réduisez le menu et les sous-menus éventuels, activez le bouton suivant avec TB_SETHOTITEM et affichez son menu. Si le dernier bouton était actif lors de la réception de cette notification, affichez le menu du premier bouton.
  • Touche Gauche. Si l’élément se trouve dans un sous-menu, réduisez-le et déplacez le focus sur son menu parent. Si l’élément n’est pas un sous-menu, réduisez le menu, activez le bouton adjacent avec TB_SETHOTITEM et affichez son menu. Si le premier bouton était actif lors de la réception de cette notification, affichez le menu du dernier bouton.
  • Flèche haut et flèche bas. Ces touches sont utilisées pour naviguer dans un menu, mais n’affectent pas directement le suivi à chaud des menus.
  • Touche d’accélérateur alt-key . Utilisez le message TB_MAPACCELERATOR pour déterminer le bouton auquel correspond le caractère clé . S’il correspond à un autre bouton que le bouton actif, réduisez le menu déroulant actuel, activez le nouveau bouton avec TB_SETHOTITEM et affichez le menu correspondant au bouton adjacent. Si le caractère Clé correspond au bouton actuellement affiché, réduisez le menu déroulant et désactivez le suivi à chaud du menu. Le bouton doit rester actif.