Developpez.com

Plus de 2 000 forums
et jusqu'à 5 000 nouveaux messages par jour

Les bases de la programmation sous Windows


précédentsommairesuivant

II. Les fenêtres

II-A. Considérations générales

Les étapes à suivre pour créer une fenêtre sont les suivantes :

  • Enregistrer une classe (ou modèle) de fenêtre

  • Créer une fenêtre (... à partir d'un modèle existant)

  • L'afficher (en effet, la fenêtre est initialement invisible)

  • Intercepter tous les messages (souris, clavier, etc.) puis les passer à la procédure de fenêtre.

Une procédure de fenêtre est une fonction chargée de traiter les messages reçus.

II-B. Enregistrer une classe de fenêtre

L'enregistrement d'une nouvelle classe de fenêtre peut se faire avec la fonction RegisterClass. Cette fonction nécessite comme paramètre l'adresse d'une structure de type WNDCLASS.

Exemple :

Enregistrer une classe de fenêtre
Sélectionnez
WNDCLASS wc;

wc.cbClsExtra     = 0;
wc.cbWndExtra     = 0;
wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
wc.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance      = <Instance de notre application>;
wc.lpfnWndProc    = <Adresse d-une procédure de fenêtre>;
wc.lpszClassName  = "Classe 1";
wc.lpszMenuName   = NULL;
wc.style          = CS_HREDRAW | CS_VREDRAW;

RegisterClass(&wc);

II-C. Créer une fenêtre, puis l'afficher

Après avoir enregistré une classe de fenêtre, on peut désormais créer une fenêtre.

Créer une fenêtre
Sélectionnez
HWND hWnd;

hWnd = CreateWindow("Classe 1", /* Classe de la fenêtre */
                    "Notre première fenêtre", /* Titre de la fenêtre */
                    WS_OVERLAPPEDWINDOW, /* Style de la fenêtre */
                    100, /* Abscisse du coin supérieur gauche */
                    100, /* Ordonnée du coin supérieur gauche */
                    600, /* Largeur de la fenêtre */
                    300, /* Hauteur de la fenêtre */
                    NULL, /* Fenêtre parent */
                    NULL, /* Menu */
                    <Instance de notre application>,
                    NULL /* Paramètres additionnels */);

Le paramètre style peut être une ou une combinaisons de constantes parmi lesquelles :

Constante Description
WS_POPUP Fenêtre pop-up (fenêtre "nue")
WS_BORDER Fenêtre comportant une bordure
WS_CAPTION Fenêtre avec barre de titre (inclut le style WS_BORDER)
WS_MINIMIZEBOX Fenêtre avec un bouton Réduire
WS_MAXIMIZEBOX Fenêtre avec un bouton Agrandir
WS_SYSMENU Fenêtre avec menu système (+ bouton Fermer)
WS_SIZEBOX (ou WS_THICKFRAME) Fenêtre redimensionnable
WS_OVERLAPPED (ou WS_TILED) Fenêtre recouvrable
WS_OVERLAPPEDWINDOW Combine tous les styles ci-dessus !
WS_CHILD Fenêtre enfant (fenêtre dans une fenêtre)
WS_VISIBLE Fenêtre initialement visible


Ensuite on affiche la fenêtre :

Afficher une fenêtre
Sélectionnez
ShowWindow(hWnd, <ShowCmd>);

Où <ShowCmd> est un entier censé indiquer la manière dont comment on souhaite afficher la fenêtre. On pourra utiliser par exemple les constantes SW_SHOW, SW_HIDE, SW_MINIMIZE, SZ_MAXIMIZE, etc. D'habitude, on lui passe le paramètre nCmdShow de WinMain afin que la fenêtre s'affiche tout comme l'utilisateur l'a demandé.

II-D. Intercepter les messages

Intercepter les messages
Sélectionnez
MSG msg;

while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

La fonction GetMessage retourne TRUE tant qu'elle n'a pas reçu le message WM_QUIT. Une application doit donc envoyer ce message pour quitter la boucle. Une fois qu'on a quitté la boucle, on termine le programme.

II-E. Ecrire la procédure de fenêtre

Exemple de procédure de fenêtre
Sélectionnez
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return 0L;
}

Le message WM_DESTROY est envoyé par Windows lorsque la fenêtre est sur le point d'être détruite (après que l'utilisateur l'a fermée par exemple). A ce moment, nous devons alors poster le message WM_QUIT. C'est ce qu'on a fait avec la fonction PostQuitMessage. Le 0 passé en argument de cette fonction sera placé dans le paramètre wParam du message. C'est en quelque sorte un entier qui indique la raison pour laquelle on a posté le message. 0 indique une fin normale. Et enfin, il ne faut jamais ignorer un message. Si le message ne nous intéresse pas, laissons à Windows le soin de s'en occuper, en appelant tout simplement DefWindowProc.

II-F. Code complet

Code complet
Sélectionnez
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASS wc;
    HWND hWnd;
    MSG msg;
    
    wc.cbClsExtra     = 0;
    wc.cbWndExtra     = 0;
    wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
    wc.hInstance      = hInstance;
    wc.lpfnWndProc    = WndProc;
    wc.lpszClassName  = "Classe 1";
    wc.lpszMenuName   = NULL;
    wc.style          = CS_HREDRAW | CS_VREDRAW;

    RegisterClass(&wc);

    hWnd = CreateWindow("Classe 1",
                        "Notre première fenêtre",
                        WS_OVERLAPPEDWINDOW,
                        100, 100, 600, 300,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);

    ShowWindow(hWnd, nCmdShow);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return 0L;
}

II-G. Attributs d'une fenêtre

II-G-1. Définition

Les attributs d'une fenêtre son sa classe, son nom, son style, sa position, sa largeur et sa hauteur, sa fenêtre parent, l'instance de l'application à laquelle elle appartient ainsi que d'autres attributs que vous avez vous-même définis.

II-G-2. Nom d'une fenêtre

Le nom d'une fenêtre, appelé également texte de la fenêtre, est une chaîne de caractères qui sert à identifier la fenêtre pour l'utilisateur. Pour une fenêtre (ou feuille), ce nom apparaît dans la barre de titre (si elle en possède évidemment). La fonction GetWindowText permet de récupérer le texte d'une fenêtre et SetWindowText de le modifier.

 
Sélectionnez
BOOL SetWindowText(HWND hWnd, LPCTSTR lpString);				
int GetWindowText(HWND hWnd, LPTSTR lpString, int nMaxCount);

On peut récupérer le handle d'une fenêtre connaissant sa classe et son nom avec la fonction :

 
Sélectionnez
HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName);

II-G-3. Style

Le style d'une fenêtre définit l'apparence et le comportement de la fenêtre. Nous avons déjà vu comment spécifier le style avec la fonction CreateWindow. La fonction CreateWindowEx permet de créer une fenêtre avec, en premier argument, un style étendu. Il s'utilise quasiment de la même manière que la fonction CreateWindow. Nous ne parlerons de ces styles que lorsque cela est vraiment nécessaire.

II-G-4. Position et dimensions

On peut déplacer et/ou redimensionner une fenêtre avec la fonction :

 
Sélectionnez
BOOL MoveWindow(HWND hWnd, int x, int y, int nWidth, int nHeight, BOOL bRepaint);

La fonction GetWindowRect permet de récupérer la position et les dimensions d'une fenêtre.

 
Sélectionnez
BOOL GetWindowRect(HWND hWnd, LPRECT lpRect);

Une structure de type RECT est composée de 4 champs de type LONG left, top, right et bottom définissant le point supérieur gauche (left, top) et le point inférieur droit (right, bottom) d'un rectangle.

Lorsqu'on crée une fenêtre, les dimensions passées à CreateWindow ou CreateWindowEx sont celles de la fenêtre et non de la zone cliente (l'intérieur de la fenêtre). On peut connaître la position de la zone cliente par rapport à son coin supérieur gauche (qui sera alors le point de coordonnées (0, 0)) à l'aide de la fonction GetClientRect qui s'utilise de la même manière que GetWindowRect. Pour ajuster un rectangle aux dimensions (et à la position) qu'il faut pour obtenir un fenêtre qui aura une zone cliente qui correspond au rectangle spécifié au départ, on pourra utiliser la fonction AdjustWindowRect (ou AdjustWindowRectEx si on veut spécifier un style étendu).

 
Sélectionnez
BOOL AdjustWindowRect(LPRECT lpRect, DWORD dwStyle, BOOL bHasMenu);

Le code suivant permet d'obtenir une fenêtre avec une zone cliente contenue dans le rectangle (100, 100) – 320 x 200 par rapport à l'écran.

 
Sélectionnez
RECT rect;
LONG x = 100, y = 200, width = 320, height = 200;

/* On veut une zone cliente comme ceci : */
rect.left = x;
rect.top = y;
rect.right = x + (width - 1);
rect.bottom = y + (height - 1);

/* On ajuste le rectangle pour qu'il corresponde à celui de la fenêtre  ... */
AdjustWindowRect(&rect, WS_BORDER | WS_CAPTION | WS_SYSMENU, FALSE);

/* ... et le tour est joué ! */
x = rect.left;
y = rect.top;
width = (rect.right - rect.left) + 1;
height = (rect.bottom - rect.top) + 1;

/* Il ne nous reste plus qu'à créer la fenêtre */
CreateWindow("Classe 1",
             "Notre première fenêtre",
             WS_BORDER | WS_CAPTION | WS_SYSMENU,
             x, y, width, height,
             NULL,
             NULL,
             hInstance,
             NULL);

II-H. Le Z Order

Le Z order est une liste qui maintient la position des fenêtres le long d'un axe z orienté vers l'extérieur de l'écran. Ainsi, la fenêtre qui se trouve au sommet du Z order se trouve au premier plan et recouvre toutes les autres fenêtres. La fonction GetForegroundWindow retourne le handle de la fenêtre se trouvant au premier plan et SetForeground de spécifier une nouvelle fenêtre.

 
Sélectionnez
HWND GetForegroundWindow(void);
BOOL SetForegroundWindow(HWND hWnd);

Le Z order est une file à priorité. Les plus prioritaires sont les fenêtres possédant le style étendu WS_EX_TOPMOST et apparaissent donc toujours en premier avant n'importe quelle autre fenêtre. Les fenêtres enfants sont groupées avec leur fenêtre parent. Lorsqu'on crée une fenêtre, Windows place cette fenêtre devant toutes les autres fenêtres de même priorité.


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 et 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.