IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

La programmation de l'interface utilisateur

La programmation de l'interface utilisateur


précédentsommairesuivant

II. Les boîtes de dialogue

II-A. Introduction

Une boîte de dialogue est une fenêtre, généralement temporaire, qui contient normalement un ou plusieurs contrôles permettant à l'utilisateur d'entrer des informations pour le programme. Cependant, au niveau de la programmation, les boîtes de dialogue ne s'utilisent pas tout à fait de la même façon que les fenêtres « normales » (bien qu'elles soient également des fenêtres) en raison justement de leur caractère temporaire (mais bien entendu, rien ne vous empêche d'avoir une boîte de dialogue comme fenêtre principale).

II-B. Deux types de boîte de dialogue

Une boîte de dialogue peut être créée avec DialogBox ou CreateDialog (qui sont en fait des macros qui utilisent CreateWindowEx en passant bien sûr les bons paramètres). La première crée une boîte de dialogue modale et la seconde une boîte de dialogue non modale. Une boîte de dialogue modale suspend le travail de sa fenêtre parent jusqu'à ce que l'utilisateur en a terminé avec. Une boîte de dialogue non modale est une fenêtre qui attend des informations venant de l'utilisateur sans suspendre le travail des autres fenêtres. Je ne vous apprends donc rien, puisque vous l'avez certainement deviné, en affirmant que DialogBox attend que l'utilisateur en ait fini avec la fenêtre (la boîte de dialogue) avant de retourner tandis que CreateDialog retourne immédiatement après l'appel.

Il faut également savoir qu'une boîte de dialogue modale sera toujours affichée par Windows que le style WS_VISIBLE ait été spécifié ou non. Par contre Windows n'affiche pas automatiquement une boîte de dialogue non modale (il faut donc avoir spécifié ou alors appeler la fonction ShowWindow).

La plupart du temps, une boîte de dialogue possède une fenêtre parent. Sauf dans le cas où la elle est utilisée comme fenêtre principale de l'application, il est en fortement conseillé de toujours spécifier une fenêtre parent lors de sa création. En effet, lorsqu'on ne spécifie aucun parent, la boîte de dialogue devient complètement autonome ce qui va évidemment compliquer sa gestion.

II-C. Traitement

La boîte de dialogue doit tout d'abord être décrite (par exemple en ressource) puis créée à l'aide de DialogBox ou CreateDialog.

 
Sélectionnez
INT_PTR DialogBox(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWnd, DLGPROC lpDialogProc);

Où lpTemplate est le nom de la boîte de dialogue qu'on veut afficher et lpDialogProc l'adresse d'une fonction qui sera la procédure de traitement des messages.

 
Sélectionnez
INT_PTR CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

Cette procédure doit retourner TRUE si le message a été traité, FALSE dans le cas contraire (sachez également que, dans les anciennes versions du SDK Windows, cette fonction ne retournait pas un INT_PTR mais BOOL). Donc si FALSE est retourné, Windows va effectuer le traitement par défaut. On n'a donc plus besoin de DefWindowProc. Et enfin, sachez qu'avec les boîtes de dialogue, le message WM_CREATE est remplacé par le message WM_INITDIALOG. Si l'on souhaite passer des paramètres à travers ce message, On utilisera DialogBoxParam ou CreateDialogParam à la place de DialogBox ou CreateDialog.

 
Sélectionnez
INT_PTR DialogBoxParam( HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWnd,
                        DLGPROC lpDialogProc, LPARAM dwInitParam );

II-D. Création

Nous allons maintenant voir comment créer un modèle (ou template) de boîte de dialogue (autrement dit : une boîte de dialogue !) en ressource. Là encore, comme vous pouvez le constater, les éditeurs de ressources sont plus que jamais d'une aide précieuse mais ici nous allons quand même taper le code nous-mêmes.

 
Sélectionnez
#include <windows.h>

MyDialog  DIALOGEX  0, 0, 100, 50
STYLE     DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION   "Ma boîte de dialogue"
{
    CTEXT          "Hello, world !", -1, 0, 8, 100, 12
    DEFPUSHBUTTON  "OK", IDOK, 25, 24, 50, 14
}

DIALOGEX est une amélioration de DIALOG (que pouvez toutefois continuer à utiliser, mais cela est-il justifié ?)

 
Sélectionnez
_name    DIALOGEX _x, _y, _width, _height
STYLE    _style
CAPTION  _caption
FONT     _pointsize, _facename, _weight, _italic, _charset
MENU     _idmenu
{
         _content
}

Pour les contrôles, la syntaxe est :

 
Sélectionnez
<TYPE DU CONTROLE> _text, _id, _x, _y, _width, _height, _style, _exstyle

Où le type du contrôle peut être LTEXT, RTEXT, CTEXT (contrôles Static), PUSHBUTTON, DEFPUSHBUTTON, RADIOBUTTON, AUTORADIOBUTTON, CHECKBOX, AUTOCHECKBOX, STATE3, AUTO3STATE, PUSHBOX, GROUPBOX, EDITTEXT, LISTBOX, COMBOXBOX ou SCROLLBAR. Bien entendu, ces contrôles s'utilisent de la même façon que les contrôles créés dynamiquement.

On peut également créer un contrôle avec le mot-clé générique CONTROL :

 
Sélectionnez
CONTROL _text, _id, _classname, _x, _y, _width, _height, _style, _exstyle

Attention ! L'unité utilisée dans les boîtes de dialogue n'est pas le pixel mais les Dialog Template Units. Ce ne sont pas des unités fixes. L'interêt d'utiliser de telles unités est de pouvoir créer des boîtes de dialogue ayant la même proportion indépendamment de la résolution de l'écran. Alors juste pour info, on appelle Dialog Base Units d'une boîte de dialogue la largeur et la hauteur moyennes des caractères dans la police utilisée. Si la boîte de dialogue utilise la police système, on peut récupérer leurs équivalents en pixels à l'aide de la fonction GetDialogBaseUnits. Sinon, un autre moyen très simple de les récupérer est d'utiliser la fonction GetTextEntentPoint32 sachant qu'on appelle largeur moyenne des caractères dans une police donnée la largeur du caractère x. Si on connaît les Dialog Base Units, on peut directement convertir les Dialog Template Units en pixels sachant que :

 
Sélectionnez
1 XDialogTemplateUnit = 1/4 (XDialogBaseUnit)
1 YDialogTemplateUnit = 1/8 (YDialogBaseUnit)

En réalité, pour convertir les Dialog Template Units en pixels, on utilisera tout simplement la fonction MapDialogRect.

II-E. Une boîte de dialogue comme fenêtre principale

Nous allons enfin voir un exemple qui affiche une boîte de dialogue comme fenêtre principale. Voici donc le code :

 
Sélectionnez
include <windows.h>

INT_PTR CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    DialogBox(hInstance, "MyDialog", NULL, DialogProc);
    return 0;
}

INT_PTR CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_INITDIALOG:
        break;
        
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case IDOK:
            SendMessage(hwnd, WM_CLOSE, 0, 0);
            break;
        }
        
        break;
        
    case WM_CLOSE:
        EndDialog(hwnd, 0);
        break;

    default:
        return FALSE;
    }
    
    return TRUE;
}

La fonction EndDialog permet de détruire une boîte de dialogue modale. La valeur passée en dernier paramètre sera utilisée par DialogBox comme valeur de retour. Dans le cas d'une boîte de dialogue non modale, on utilise plutôt la fonction DestroyWindow (en fait, EndDialog utilise en interne DestroyWindow mais après avoir recupéré la valeur que DialogBox doit retourner).

II-F. Les boîtes de dialogue communes

Dans les paragraphes précédents nous avons appris à utiliser des boîtes de dialogue que nous avons nous-mêmes créées. Ici ce qui nous intéressera ce sont les boîtes de dialogue communes, c'est-à-dire celles qui sont fournies par Windows. Il s'agit des boîtes de dialogue Ouvrir, Enregistrer (Enregistrer sous), Imprimer, etc. En particulier, sachez que le boîtes de dialogue Ouvrir et Enregistrer sous sont en fait les mêmes (ou presque) ! Pour afficher la boîte de dialogue (Ouvrir ou Enregistrer sous), on initialise une structure de type OPENFILENAME qui décrit la boîte que l'on veut afficher ensuite on appelle GetOpenFileName pour afficher la boîte de dialogue Ouvrir et GetSaveFileName pour afficher la boîte de dialogue Enregistrer sous (ces boîtes de dialogue ont la même apparence, la seule véritable différence vient du texte du bouton par défaut qui est Ouvrir pour la boîte de dialogue Ouvrir et Enregistrer pour la boîte de dialogue Enregistrer sous), et c'est aussi simple que cela ! Par exemple :

 
Sélectionnez
OPENFILENAME ofn;

char lpszFile[MAX_PATH] = "";
char lpszFileTitle[MAX_PATH] = "";

ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize     = sizeof (OPENFILENAME);
ofn.hwndOwner       = hwnd;
ofn.lpstrFilter     = "Texte (*.txt)\0*.txt\0Tous (*.*)\0*.*\0";
ofn.lpstrFile       = lpszFile;
ofn.nMaxFile        = sizeof(lpszFile) / sizeof(lpszFile[0]);
ofn.lpstrFileTitle  = lpszFileTitle;
ofn.nMaxFileTitle   = sizeof(lpszFileTitle) / sizeof(lpszFileTitle[0]);
ofn.Flags           = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_CREATEPROMPT;

if (GetOpenFileName(&ofn))
     MessageBox(hwnd, lpszFile, lpszFileTitle, MB_OK);
else
     MessageBox(hwnd, "Opération annulée", "GetOpenFileName", MB_OK);

Sachez cependant que OPENFILENAME est une structure particulièrement riche et que nous n'avons ici utilisé que quelques uns de ses champs seulement. Elle est définie dans commdlg.h (inclus par windows.h) de la manière suivante :

 
Sélectionnez
typedef struct tagOFN {
    DWORD          lStructSize;        /* [in]     Taille de la structure                                   */
    HWND           hwndOwner;          /* [in]     Fenêtre parent de la boîte de dialogue                   */
    HINSTANCE      hInstance;          /* [in]     Handle d'un module contenant une boîte de dialogue (1)   */
    LPCTSTR        lpstrFilter;        /* [in]     Spécifie les filtres disponibles                         */
    LPTSTR         lpstrCustomFilter;  /* [in/out] Contient le filtre préféré de l'utilisateur              */
    DWORD          nMaxCustFilter;     /* [in]     Largeur du buffer lpstrCustomFilter                      */
    DWORD          nFilterIndex;       /* [in/out] Contient l'index du filtre sélectionné (2)               */
    LPTSTR         lpstrFile;          /* [in/out] Contient le nom du fic. Doit être initialisé             */
    DWORD          nMaxFile;           /* [in]     Largeur du buffer lpstrFile                              */
    LPTSTR         lpstrFileTitle;     /* [in/out] Contient le nom et l'ext. seulement du fic.              */
    DWORD          nMaxFileTitle;      /* [in]     Largeur du buffer lpstrFileTitle                         */
    LPCTSTR        lpstrInitialDir;    /* [in]     Pointeur vers le chemin du répertoire initial            */
    LPCTSTR        lpstrTitle;         /* [in]     Titre (caption) de la boîte de dialogue                  */
    DWORD          Flags;              /* [in/out] Style et comportement de la boîte de dialogue            */
    WORD           nFileOffset;        /* [out]    Indice du 1er caractère du nom du fic. dans lpstrFile    */
    WORD           nFileExtension;     /* [out]    Indice du 1er caractère de l'ext. du fic. dans lpstrFile */
    LPCTSTR        lpstrDefExt;        /* [in]     Ext. par défaut (3)                                      */
    LPARAM         lCustData;          /* [in]     Paramètre à passer la lpfnHook via le msg WM_INITDIALOG  */
    LPOFNHOOKPROC  lpfnHook;           /* [in]     DlgProc de la boîte de dialogue (4)                      */
    LPCTSTR        lpTemplateName;     /* [in]     Nom de la boîte de dialogue à charger                    */
    
#if (_WIN32_WINNT >= 0x0500)
    void *         pvReserved;         /* [x]      Reservé. Doit être NULL                                  */
    DWORD          dwReserved;         /* [x]      Reservé. Doit être 0                                     */
    DWORD          FlagsEx;            /* [in]     Flags étendus                                            */
#endif /* (_WIN32_WINNT >= 0x0500) */
    
} OPENFILENAME, *LPOPENFILENAME;

/* (1) : Requiert le flag OFN_ENABLETEMPLATEHANDLE.                                                         */
/* (2) : En entrée, 0 sélectionne le filtre préféré.                                                        */
/* (3) : Vous pouvez spéifiez une chaîne de 3 caractères tout au plus. Omettez le point.                    */
/* (4) : Requiert le flag OFN_ENABLEHOOK.                                                                   */


Voici une liste des flags les plus courants :

OFN_ALLOWMULTISELECT : Autorise la sélection multiple.

OFN_CREATEPROMPT : Indique que l'utilisateur peut entrer un nom de fichier qui n'existe pas et dans ce cas il sera invité à confirmer son choix.

OFN_EXPLORER : Impose le style Explorer. En fait ce style est appliqué par défaut mais il est parfois annulé par certains flags. Ce flag permet de toujours utiliser le style Explorer.

OFN_FILEMUSTEXIST : Utilisable uniquement dans une boîte de dialogue Ouvrir. Permet de spécifier que l'utilisateur doit entrer un nom de fichier existant. Inclut le flag OFN_PATHMUSTEXIST.

OFN_FORCESHOWHIDDEN : Windows 2000 et plus récents uniquement. Affiche les dossiers et fichiers cachés et/ou systèmes, indépendamment des préférences de l'utilisateur.

OFN_HIDEREADONLY : N'a de sens que dans une boîte de dialogue Ouvrir. Cache l'option « ouvrir en lecture seulement ».

OFN_NODEREFERENCELINKS : Par défaut, si l'utilisateur sélectionne un raccourci (.lnk), le champ lpstrFile contient le chemin vers le fichier pointé par le lien. Le flag OFN_NODEREFERENCELINKS permet de spécifier que l'on désire dans un tel cas avoir le nom du lien et non celui du fichier pointé.

OFN_OVERWRITEPROMPT : Dans une boîte de dialogue Enregistrer sous, provoque une demande de confirmation si l'utilisateur sélectionne un nom de fichier existant.

OFN_PATHMUSTEXIST : Spécifie que l'utilisateur doit utiliser des caractères valides uniquement.

OFN_READONLY : N'a de sens que dans une boîte de dialogue Ouvrir. Coche l'option « ouvrir en lecture seulement ». Au retour de la fonction, ce flag indique l'état de ladite option.


précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Melem. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.