Guide pratique pour créer des Assistants

Un Assistant est un type de feuille de propriétés qui fournit un moyen simple et puissant de guider les utilisateurs dans une procédure.

Les Assistants sont l’une des clés pour simplifier l’expérience utilisateur. Ils vous permettent d’effectuer une opération complexe, telle que la configuration d’une application, et de la décomposer en une série d’étapes simples. À chaque étape du processus, vous pouvez expliquer ce qu’il faut faire et afficher des contrôles qui permettent à l’utilisateur de faire des sélections et d’entrer du texte.

Un Assistant est en fait un type de feuille de propriétés. Fondamentalement, une feuille de propriétés est un conteneur pour une collection de pages, où chaque page est une boîte de dialogue distincte. Alors que la plupart des feuilles de propriétés permettent à l’utilisateur d’accéder à n’importe quelle page à tout moment, les Assistants présentent des pages en séquence. Au lieu des onglets, les boutons sont utilisés pour avancer ou reculer. L’ordre d’affichage des pages est contrôlé par l’application et peut être modifié en fonction de l’entrée utilisateur.

Il existe deux styles principaux d’Assistant : l’ancien style Wizard97 et le style Aero introduit dans Windows Vista. Pour des illustrations, consultez À propos des feuilles de propriétés. (Un troisième style, utilisant uniquement l’indicateur PSH_WIZARD ou PSH_WIZARD_LITE, présente une séquence simple de feuilles de propriétés sans en-têtes ni filigranes.)

Remarque

Un « filigrane » dans le contexte des Assistants est une bitmap qui apparaît dans la marge gauche de certaines pages.

 

Dans ce document, on suppose en général que vous implémentez un Assistant pour un système avec la version 5.80 ou ultérieure des contrôles courants. Si vous tentez d’utiliser le style Wizard97 avec les versions antérieures des contrôles courants, votre application peut compiler, mais elle ne s’affiche pas correctement. Pour une méthode de création d’un Assistant compatible Avec Wizard97 sur des systèmes antérieurs, consultez la section Assistants rétro-compatibles plus loin dans cette rubrique.

Bon à savoir

Technologies

Prérequis

  • C/C++
  • Programmation de l’interface utilisateur Windows

Instructions

Implémentation de l’Assistant

L’implémentation d’un Assistant est similaire à l’implémentation d’une feuille de propriétés régulière. Fondamentalement, il s’agit de définir l’un des indicateurs ou combinaisons d’indicateurs suivants dans la structure PROPSHEETHEADER qui définit la feuille de propriétés.

Indicateur Style
PSH_WIZARD Assistant simple sans en-têtes ni bitmaps.
PSH_WIZARD_LITE Semblable à PSH_WIZARD, avec quelques différences mineures dans l’apparence ; Par exemple, le séparateur au-dessus des boutons s’étend sur toute la largeur de la fenêtre.
PSH_WIZARD97 Assistant Wizard97 avec des en-têtes (facultatifs), des bitmaps d’en-tête et des filigranes.
PSH_WIZARD | PSH_AEROWIZARD Un Assistant Aero. Les Assistants Aero n’utilisent pas de filigranes ou de bitmaps d’en-tête. Ils nécessitent le modèle STA (Single-Threaded Apartment).

 

La procédure de base pour l’implémentation d’un assistant est la suivante :

  1. Créez un modèle de boîte de dialogue pour chaque page.
  2. Définissez les pages en créant une structure PROPSHEETPAGE pour chaque page. Cette structure définit la page et contient des pointeurs vers le modèle de boîte de dialogue et toutes les bitmaps ou autres ressources.
  3. Faites passer la structure PROPSHEETPAGE créée à l’étape précédente à la fonction CreatePropertySheetPage pour créer le handle HPROPSHEETPAGE de la page.
  4. Définissez l’assistant en lui créant une structure PROPSHEETHEADER.
  5. Faites passer la structure PROPSHEETHEADER à la fonction PropertySheet pour afficher l’assistant.
  6. Implémentez des procédures de boîte de dialogue pour chaque page, afin de gérer les messages de notification à partir des contrôles de la page et des boutons de l’assistant et pour traiter d’autres messages Windows.

Créer les modèles de boîte de dialogue

Il existe deux types basiques de page d’assistant : extérieur et intérieur. Les pages extérieures sont les pages de présentation (accueil) et de finalisation. Toutes les autres sont des pages intérieures.

Modèles de boîte de dialogue de page extérieure

Les dispositions de base des pages d’introduction et de finalisation sont identiques. L’illustration suivante montre un exemple de page de présentation Wizard97, avec un filigrane d’espace réservé.

screen shot showing a wizard page with a graphic on the left, title and body text on the right, and back, next and cancel buttons at the bottom

Pour les pages extérieures Wizard97, le modèle de boîte de dialogue est de 317 x 193 unités de dialogue. Il remplit tout l’assistant, à l’exception de la légende et de la bande en bas qui contient les boutons Précédent, Suivant et Annuler. Le côté gauche du modèle, qui est réservé à une bitmap « filigrane », ne doit contenir aucun contrôle. Le filigrane est spécifié dans la structure PROPSHEETHEADERde l’assistant et est ajouté automatiquement à la page. Vous devez lui ménager un espace lors de la conception du modèle de ressource.

Lorsque vous créez la bitmap de filigrane, gardez à l’esprit que la taille de la boîte de dialogue peut augmenter si, par exemple, l’utilisateur choisit une police système volumineuse. Différentes langues ont également tendance à avoir des mesures de police différentes. Lorsque la page grandit, la zone réservée au filigrane grandit à proportion. Toutefois, vous ne pouvez pas modifier la bitmap de filigrane, qui ne s’étire pas non plus pour remplir la zone plus étendue. Au lieu de cela, la bitmap est conserve sa taille d’origine dans la partie supérieure gauche de la zone réservée. La partie de la zone réservée plus étendue qui n’est pas couverte par le filigrane est automatiquement remplie avec la couleur du pixel supérieur gauche de la bitmap.

Si vous devez avoir des bitmaps de filigrane de taille différente pour différentes mesures de police, voici deux solutions possibles :

  • Identifiez les mesures de police avant de créer l’assistant et spécifiez une bitmap de filigrane de taille appropriée.
  • Ne spécifiez pas de bitmap de filigrane lorsque vous créez l’assistant. Wizard97 laisse la zone de filigrane vide. Dessinez ensuite une bitmap de taille appropriée sur la zone réservée au filigrane.

Vous pouvez placer des contrôles dans la zone à droite du filigrane comme vous le feriez pour une boîte de dialogue normale. La couleur d’arrière-plan de cette zone est déterminée par le système et ne nécessite aucune action de votre part. Vous placez généralement deux contrôles statiques dans cette zone. La partie supérieure contient le titre et utilise une police en gras volumineux (12 points Verdana Bold pour Wizard97). L’autre, qui est destiné au texte explicatif, utilise la police de boîte de dialogue standard.

La principale différence entre les pages de présentation et de finalisation réside dans les boutons de l’assistant et le texte des contrôles statiques. Les pages de présentation ont normalement des boutons Suivant et Précédent, le bouton Suivant étant seul activé. Les pages de finalisation ont le bouton Précédent activé et le bouton Suivant est remplacé par un bouton Terminer.

Remarque

Dans les assistants Aero, le bouton Précédent est remplacé par un bouton de flèche dans la barre de légende.

 

Vous pouvez modifier le texte sur le bouton Terminer en envoyant à l’assistant un message PSM_SETFINISHTEXT. Par défaut, le bouton Terminer n’inclut pas d’accélérateur de clavier. Pour définir un raccourci clavier, incluez une esperluette dans la chaîne de texte que vous transmettez à PSM_SETFINISHTEXT. Par exemple, « &Finish » définit « F » comme accélérateur de clavier.

Modèles de boîte de dialogue de page intérieure

Les pages intérieures ont une apparence quelque peu différente de celle des pages extérieures. L’illustration suivante montre un exemple de page intérieure Wizard97, avec une bitmap d’en-tête d’espace réservé.

screen shot of a wizard page with title and subtitle text and a graphic at the top, text in the middle, and buttons on the bottom

La zone d’en-tête située en haut de la page est gérée par la feuille de propriétés. Elle n’est donc pas incluse dans le modèle. Le contenu de l’en-tête est spécifié dans la structure PROPSHEETPAGE de la page et la structure PROPSHEETHEADER de l’assistant. Étant donné que la page intérieure doit tenir entre l’en-tête et les boutons, le modèle de boîte de dialogue Wizard97 est de 317 x 143 unités de dialogue, un peu plus petit que le modèle pour les pages extérieures.

L’illustration suivante montre un Assistant Aero créé à partir du même modèle.

screen shot that differs from the previous one by having a title area at the top, and only next and cancel buttons at the bottom

Définir les pages de l’Assistant

Une fois que vous avez créé les modèles de boîte de dialogue et les ressources associées telles que les bitmaps et les tables de chaînes, vous pouvez créer les pages de feuille de propriétés. La procédure est similaire à celle s’appliquant aux feuilles de propriétés standard. Tout d’abord, renseignez les membres appropriés d’une structure PROPSHEETPAGE. (Certains membres sont spécifiques aux assistants.) Appelez ensuite la fonction CreatePropertySheetPage pour créer le handle HPROPSHEETPAGE de la page.

Les indicateurs associés à l’assistant suivants peuvent être définis dans le membre dwFlags de la structure PROPSHEETPAGE.

Indicateur Description
PSP_HIDEHEADER Définissez cet indicateur pour les pages extérieures de Wizard97. L’en-tête n’est pas affiché et un filigrane peut être affiché.
PSP_USEHEADERTITLE Définissez cet indicateur pour les pages intérieures pour placer un titre dans la zone d’en-tête dans Wizard97 ou en haut de la zone client dans un Assistant Aero.
PSP_USEHEADERSUBTITLE Définissez cet indicateur pour que les pages intérieures placent un sous-titre dans la zone d’en-tête de Windows97.

 

Si vous avez défini PSP_USEHEADERTITLE ou PSP_USEHEADERSUBTITLE, affectez respectivement le titre et le texte du sous-titre aux membres pszHeaderTitle et pszHeaderSubtitle. Lorsque vous affectez des chaînes de texte aux membres des structures PROPSHEETPAGE et PROPSHEETHEADER, vous pouvez affecter un pointeur de chaîne ou utiliser la macro MAKEINTRESOURCE pour attribuer une valeur à partir d’une ressource de chaîne. La ressource de chaîne est chargée à partir du module spécifié dans le membre hInstance de la structure PROPSHEETHEADER de l’assistant.

Lorsque vous appelez CreatePropertySheetPage pour créer une page, affectez le résultat à un élément d’un tableau de handles HPROPSHEETPAGE. Ce tableau est utilisé lors de la création de la feuille de propriétés. L’index de tableau du handle d’une page détermine l’ordre par défaut dans lequel il est affiché. Une fois que vous avez créé le handle HPROPSHEETPAGE d’une page, vous pouvez réutiliser la même structure PROPSHEETPAGE pour créer la page suivante en affectant de nouvelles valeurs aux membres appropriés.

Une autre façon de créer des pages consiste à utiliser des structures PROPSHEETPAGE distinctes pour chaque page et à créer un tableau de structures. Ce tableau est utilisé au lieu d’un tableau de handles HPROPSHEETPAGE lors de la création de la feuille de propriétés. L’utilisation de structures PROPSHEETPAGE distinctes élimine la nécessité d’appeler CreatePropertySheetPage, mais utilise plus de mémoire. Sinon, il n’existe aucune différence significative entre les deux approches.

L’exemple suivant définit une page Wizard97 intérieure en affectant des valeurs à une structure PROPSHEETPAGE. Dans cet exemple, les modèles de titre, de sous-titre et de boîte de dialogue de la page sont tous identifiés par leurs ID de ressource. La fonction CreatePropertySheetPage est ensuite appelée pour créer le handle HPROPSHEETPAGE de la page. Étant donné qu’il s’agit de la deuxième page à s’afficher, le handle est affecté au tableau de handles, ahpsp, avec un index de 1.

// g_hInstance is the global HINSTANCE of the application.
// IntPage1DlgProc is the dialog procedure for this page.
// ahpsp is an array of HPROPSHEETPAGE handles.

PROPSHEETPAGE psp = { sizeof(psp) };

psp.hInstance         = g_hInstance;
psp.dwFlags           = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
psp.lParam            = (LPARAM) &wizdata;
psp.pszHeaderTitle    = MAKEINTRESOURCE(IDS_TITLE1);
psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_SUBTITLE1);
psp.pszTemplate       = MAKEINTRESOURCE(IDD_INTERIOR1);
psp.pfnDlgProc        = IntPage1DlgProc;

ahpsp[1] = CreatePropertySheetPage(&psp);

Données de page personnalisées

Lorsque vous créez une page, vous pouvez lui attribuer des données personnalisées à l’aide du membre lParam de la structure PROPSHEETPAGE, généralement en affectant un pointeur à une structure définie par l’utilisateur.

Lorsque la page est sélectionnée pour la première fois, sa procédure de boîte de dialogue reçoit un message WM_INITDIALOG. La valeur lParam du message redirige vers une copie de la structure PROPSHEETPAGE de la page, à partir de laquelle vous pouvez récupérer les données personnalisées. Vous pouvez ensuite stocker ces données à utiliser dans les messages suivants à l’aide de SetWindowLongPtr avec GWL_USERDATA comme paramètre d’index. Plusieurs pages peuvent avoir un pointeur vers les mêmes données, et toute modification apportée aux données effectuées par une page est accessible aux autres pages dans leurs procédures de boîte de dialogue.

Définir la feuille de propriétés de l’Assistant

Comme pour les feuilles de propriétés ordinaires, vous définissez la feuille de propriétés de l’assistant en remplissant les membres d’une structure PROPSHEETHEADER. Cette structure vous permet de spécifier les pages qui composent l’assistant et l’ordre par défaut dans lequel ils sont affichés, ainsi que plusieurs paramètres associés. Vous lancez ensuite l’assistant en appelant la fonction PropertySheet.

Dans le style Wizard97, le membre pszCaption de la structure PROPSHEETHEADER est ignoré. Au lieu de cela, l’assistant affiche la légende spécifiée dans le modèle de boîte de dialogue de la page active. Si le modèle n’a pas de légende, la légende de la page précédente est affichée. Ainsi, pour afficher la même légende sur toutes les pages, spécifiez la légende de la page d’introduction dans le modèle.

Dans le style Aero Wizard, la légende de la boîte de dialogue est extraite de pszCaption.

Si vous avez créé un tableau de handles HPROPSHEETPAGE pour vos pages, affectez le tableau au membre phpage. Si vous avez plutôt créé un tableau de structures PROPSHEETPAGE, affectez le tableau au membre ppsp et définissez l’indicateur PSH_PROPSHEETPAGE dans le membre dwFlags.

L’exemple suivant affecte des valeurs à psh, une structure PROPSHEETHEADER et appelle la fonction PropertySheet pour lancer l’assistant. L’assistant de style Wizard97 dispose à la fois de graphiques en filigrane et d’en-tête, spécifiés par leurs ID de ressource. Le tableau ahpsp contient tous les handles HPROPSHEETPAGE et définit l’ordre par défaut dans lequel ils sont affichés.

// g_hInstance is the global HINSTANCE of the application.
// ahpsp is an array of HPROPSHEETPAGE handles.

PROPSHEETHEADER psh = { sizeof(psh) };

psh.hInstance      = g_hInstance;
psh.hwndParent     = NULL;
psh.phpage         = ahpsp;
psh.dwFlags        = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
psh.pszbmHeader    = MAKEINTRESOURCE(IDB_BANNER);
psh.nStartPage     = 0;
psh.nPages         = 4;

PropertySheet(&psh);

Procédure de la boîte de dialogue

Chaque page de l’assistant a besoin d’une procédure de boîte de dialogue pour traiter les messages Windows, en particulier les notifications de ses contrôles et de l’assistant. Les trois messages que presque tous les assistants doivent pouvoir gérer sont WM_INITDIALOG, WM_DESTROY et WM_NOTIFY.

Le message WM_NOTIFY est reçu avant l’affichage de la page et lors d’un clic sur l’un des boutons de l’assistant. Le paramètre lParam du message est un pointeur vers une structure d’en-tête NMHDR. L’ID de la notification est contenu dans le membre de code de la structure. Les quatre notifications que la plupart des assistants doivent gérer sont les suivantes :

Code Description
PSN_SETACTIVE Envoyée avant l’affichage de la page.
PSN_WIZBACK Envoyée lors d’un clic sur le bouton Précédent.
PSN_WIZNEXT Envoyé lors d’un clic sur le bouton Suivant.
PSN_WIZFINISH Envoyé lors d’un clic sur le bouton Terminer.

 

Gérer WM_INITDIALOG et WM_DESTROY

Lorsqu’une page est sur le point d’être affichée pour la première fois, sa procédure de boîte de dialogue reçoit un message WM_INITDIALOG. La gestion de ce message permet à l’assistant d’effectuer toutes les tâches d’initialisation nécessaires, telles que le stockage de données personnalisées ou la définition de polices.

Lorsque la feuille de propriétés est détruite, vous recevez un message WM_DESTROY. L’assistant est automatiquement détruit par le système, mais la gestion de ce message vous permet d’effectuer tout nettoyage nécessaire.

Gérer PSN_SETACTIVE

Le code de notification PSN_SETACTIVE est envoyé chaque fois qu’une page est sur le point d’être rendue visible. La première fois qu’une page est visitée, PSN_SETACTIVE suit le message WM_INITDIALOG. Si la page est ensuite revisitée, elle reçoit uniquement une notification de PSN_SETACTIVE. Cette notification est généralement gérée pour initialiser les données de la page et activer les boutons appropriés.

Par défaut, l’assistant affiche les boutons Précédent, Suivantet Annuler , avec tous les boutons activés. Pour désactiver un bouton ou afficher Terminer au lieu de Suivant, vous devez envoyer un message PSM_SETWIZBUTTONS. Une fois ce message envoyé, l’état des boutons est conservé jusqu’à ce qu’il soit modifié par un autre message PSM_SETWIZBUTTONS, même si une nouvelle page est sélectionnée. En règle générale, tous les gestionnaires PSN_SETACTIVE envoient ce message pour s’assurer que les boutons sont à l’état correct sur toutes les pages.

Vous pouvez modifier l’état du bouton avec ce message à tout moment. Par exemple, vous souhaiterez peut-être que le bouton Suivant soit initialement désactivé. Une fois qu’un utilisateur a entré toutes les informations nécessaires, vous pouvez envoyer un autre message PSM_SETWIZBUTTONS pour activer le bouton Suivant et permettre à l’utilisateur de passer à la page suivante.

Le fragment de code suivant utilise la macro PropSheet_SetWizButtons pour activer les boutons Précédent et Suivant sur une page intérieure avant son affichage.

case WM_NOTIFY :
    {
        LPNMHDR pnmh = (LPNMHDR)lParam;
        
        switch(pnmh->code)
        {
        
        ...
        
        case PSN_SETACTIVE :
        
            ...
            
            // This is an interior page.
            PropSheet_SetWizButtons(hwnd, PSWIZB_NEXT | PSWIZB_BACK);
            
            ...
        }
    ...
    
    }

Gérer PSN_WIZNEXT, PSNWIZBACK et PSN_WIZFINISH

Lors d’un clic sur un bouton Suivant ou Précédent, vous recevez un code de notification PSN_WIZNEXT ou PSN_WIZBACK. Par défaut, l’assistant accède automatiquement à la page suivante ou précédente dans l’ordre défini lors de la création de la feuille de propriétés. Une raison courante de gérer ces notifications est d’empêcher l’utilisateur de changer de page ou de remplacer l’ordre de page par défaut.

Pour empêcher l’utilisateur de changer de page, gérez la notification de bouton, appelez la fonction SetWindowLong avec la valeur DWL_MSGRESULT définie sur –1 et retournez TRUE. Par exemple :

case PSN_WIZNEXT :

        ...
        
        // Do not go to the next page yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, -1);
        
        return TRUE;
        
        ...

Pour remplacer l’ordre standard et accéder à une page particulière, appelez SetWindowLong avec la valeur DWL_MSGRESULT définie sur l’ID de ressource de la boîte de dialogue de la page, puis retournez TRUE. Par exemple :

case PSN_WIZNEXT :

        ...
        
        // Go straight to the completion page.
        SetWindowLong(hwnd, DWL_MSGRESULT, IDD_FINISH);
        
        return TRUE;
        
        ...

Lors d’un clic sur le bouton Terminer ou Annuler, vous recevez respectivement un code de notification PSN_WIZFINISH ou PSN_RESET. Lors d’un clic sur l’un de ces boutons, l’assistant est automatiquement détruit par le système. Toutefois, vous pouvez gérer ces notifications si vous devez effectuer des tâches de nettoyage avant la destruction de l’assistant. Pour empêcher la destruction de l’assistant lorsque vous recevez une notification PSN_WIZFINISH, appelez SetWindowLong avec la valeur DWL_MSGRESULT définie sur TRUE et renvoyez TRUE. Par exemple :

case PSN_WIZFINISH :

        ...
        
        // Not finished yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
        
        return TRUE;
        
        ...

Assistants rétro-compatibles

La section précédente suppose que vous implémentez un assistant pour un système avec la version 5 ou ultérieure des contrôles courants.

Si vous écrivez un assistant pour les systèmes avec des versions antérieures des contrôles courants, la plupart des fonctionnalités décrites dans la section précédente ne seront pas disponibles. Un certain nombre de membres des structures PROPSHEETHEADER et PROPSHEETPAGE utilisées par le style Wizard97 sont pris en charge uniquement par les contrôles courants version 5 et ultérieures. Toutefois, il est toujours possible d’implémenter un assistant rétro-compatible avec une apparence similaire à celle du style Wizard97. Pour ce faire, vous devez implémenter explicitement les éléments suivants :

  • Ajoutez le graphique en filigrane au modèle de boîte de dialogue pour vos pages de présentation et de finalisation.
  • Donnez la même taille à tous vos modèles. Il n’existe aucune zone d’en-tête distincte définie par le système pour les pages intérieures.
  • Créez explicitement la zone d’en-tête de la page intérieure sur vos modèles.
  • N’utilisez pas de graphique d’en-tête, car il peut entrer en conflit avec le titre ou le sous-titre si l’assistant change de taille.

Pour plus d’informations sur les assistants rétro-compatibles, consultez l’assistant rétro-compatible Wizzard 97.

Notes

Pour une présentation complète des problèmes de conception relatifs à Wizard97, consultez les spécifications Wizard97, ailleurs dans le SDK Windows. Ce document contient des instructions pour des éléments tels que les dimensions des boîtes de dialogue, les dimensions et les couleurs de bitmap, ainsi que le positionnement des contrôles.

Utilisation de feuilles de propriétés

Démonstration des contrôles courants Windows (CppWindowsCommonControls)