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

API Windows en C

Les contextes de périphériques

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Nous allons voir dans ce nouveau chapitre les sorties écrans, ou plutôt l'écriture sur les fenêtres. Sous Windows on parlera plutôt de dessin.
Windows a les facultés de pouvoir dessiner sur n'importe quel périphérique de sortie (écran, imprimante...) sans se préoccuper de comment il fonctionne. Ce sont les drivers qui font le travail.
Pour dessiner sous Windows on doit obtenir du périphérique sur lequel l'on veut dessiner un contexte de périphérique (DC). Pour simplifier, nous allons nous représenter le contexte de périphérique comme une surface de dessin que nous aura fourni la fenêtre sur laquelle l'on veut dessiner.

Image non disponible

II. Dessin

Nous allons reprendre l'exemple du chapitre 1. Nous y interceptons le message WM_KEYDOWN qui est envoyé à la procédure de fenêtre quand on appuie sur une touche et qu'elle possède le focus clavier. Pour une fenêtre (ou contrôle) avoir le focus clavier signifie qu'elle est la fenêtre active et que par conséquent, c'est elle qui reçoit les entrées clavier.

 
Sélectionnez
    switch (uMsg)
    {       
        case WM_KEYDOWN :
            {
              int y;
              char st[] = "Bienvenue sur Developpez.com" ;
              HDC hdc = GetDC(hwnd);
              SetBkMode(hdc, TRANSPARENT);
              for(y=10; y <= 200; y += 20)
                                          TextOut(hdc, 10, y, st , lstrlen(st));
              ReleaseDC(hwnd, hdc);
              return 0;
            }

À la réception de ce message, nous écrirons 10 lignes avec la chaîne de caractères : "Bienvenue sur Developpez.com" décalées de 20 pixels verticalement les unes par rapport aux autres. Première opération, obtenir le handle d'un contexte de périphérique (HDC) pour la fenêtre en question à l'aide de la fonction GetDC qui reçoit comme paramètre de handle de la fenêtre sur laquelle l'on veut écrire ou dessiner. Quand on écrit ou dessine sous Windows, le fond est aussi peint par la même occasion. Comme il ne nous importe pas pour l'instant nous le mettrons transparent à l'aide de la fonction SetBkMode qui recevra donc comme paramètres le handle du contexte de périphérique et une constante de mode : TRANSPARENT. Nous pouvons alors écrire notre chaîne de caractères à l'aide de la fonction TextOut qui reçoit le handle du contexte de périphérique comme premier paramètre. Les deux suivants étant les coordonnées d'affichage (x,y). Le suivant étant un pointeur sur la chaîne de caractères à dessiner. Le dernier étant la longueur de la chaîne de caractères retournée par la fonction lstrlen (fonction de l'API Windows).
Nous devons libérer le contexte de périphérique après son utilisation. C'est le rôle de la fonction ReleaseDC.

Mais voilà, un problème se pose, à chaque fois que la fenêtre est cachée par une autre, le texte qui s'y trouve disparaît. Ce qui est fort ennuyeux. Dans le cas présent vous pouvez bien le faire réapparaître en appuyant une autre fois sur une touche, mais ce n'est pas très pratique. Mais alors, comment faire ? Et bien c'est encore un message qui intervient WM_PAINT :

III. Le message WM_PAINT

À chaque fois qu'une fenêtre ou une partie de fenêtre a besoin de se redessiner Windows lui envoie un message WM_PAINT. Il nous suffira donc d'intercepter ce message dans sa procédure de fenêtre et d'appeler les fonctions de dessin suite à ce message :

 
Sélectionnez
        case WM_PAINT :
            {
              int y;
              char st[] = "Bienvenue sur Developpez.com" ;
              HDC hdc = GetDC(hwnd);
              SetBkMode(hdc, TRANSPARENT);
              for(y=10; y <= 200; y += 20)
                                          TextOut(hdc, 10, y, st , lstrlen(st));
              ReleaseDC(hwnd, hdc);
              return 0;
            }

Miracle ! Le texte ne disparaît plus.
Il est redessiné à chaque fois que cela est nécessaire.
Il subsiste un scintillement désagréable, surtout lors des redimensionnements. Ceci est dû au fait que la zone client de la fenêtre est entièrement redessinée à chaque message WM_PAINT qu'elle reçoit. Une solution existe pour éliminer ce phénomène. C'est de redessiner seulement la partie de la fenêtre qui en a besoin. On l'appelle cette partie la zone invalide.
Pour cela, il faut obtenir le handle du contexte de périphérique avec la fonction BeginPaint au lieu de GetDC. Cette fonction nécessite un pointeur sur une variable préalablement définie de type (struct PAINTSTRUCT) comme paramètre afin d'y mémoriser des informations.

 
Sélectionnez
        case WM_PAINT :
            {
              int y;
              char st[] = "Bienvenue sur Developpez.com" ;
              PAINTSTRUCT ps;
              HDC hdc = BeginPaint(hwnd, &ps);
              SetBkMode(hdc, TRANSPARENT);
              for(y=10; y <= 200; y += 20)
                                          TextOut(hdc, 10, y, st , lstrlen(st));
              EndPaint(hwnd, &ps);
              return 0;
            }

Tout handle de contexte de périphérique obtenu avec BeginPaint doit être libéré avec EndPaint.
Remarque : les fonctions BeginPaint et EndPaint ne peuvent être utilisées qu'exclusivement à la réception d'un message WM_PAINT.

IV. Code complet

 
Sélectionnez
#include <windows.h>

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
                                                LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    MSG msg;
    WNDCLASS wc;

    wc.style = 0;
    wc.lpfnWndProc = MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hinstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
    wc.lpszMenuName =  NULL;
    wc.lpszClassName = "MaWinClass";

    if(!RegisterClass(&wc)) return FALSE;

    hwnd = CreateWindow("MaWinClass", "Titre", WS_OVERLAPPEDWINDOW,
                                   CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
                                                   NULL, NULL, hinstance, NULL);
    if (!hwnd) return FALSE;

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
/******************************************************************************/

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        /* mis en commentaire et remplacé par WM_PAINT
        case WM_KEYDOWN :
            {
              int y;
              char st[] = "Bienvenue sur Developpez.com" ;
              HDC hdc = GetDC(hwnd);
              SetBkMode(hdc, TRANSPARENT);
              for(y=10; y <= 200; y += 20)
                                          TextOut(hdc, 10, y, st , lstrlen(st));
              ReleaseDC(hwnd, hdc);
              return 0;
            }      */

        /* mis en commentaire et remplacé par WM_PAINT suivant
        case WM_PAINT :
            {
              int y;
              char st[] = "Bienvenue sur Developpez.com" ;
              HDC hdc = GetDC(hwnd);
              SetBkMode(hdc, TRANSPARENT);
              for(y=10; y <= 200; y += 20)
                                          TextOut(hdc, 10, y, st , lstrlen(st));
              ReleaseDC(hwnd, hdc);
              return 0;
            }      */

        case WM_PAINT :
            {
              int y;
              char st[] = "Bienvenue sur Developpez.com" ;
              PAINTSTRUCT ps;
              HDC hdc = BeginPaint(hwnd, &ps);
              SetBkMode(hdc, TRANSPARENT);
              for(y=10; y <= 200; y += 20)
                                          TextOut(hdc, 10, y, st , lstrlen(st));
              EndPaint(hwnd, &ps);
              return 0;
            }

        case WM_DESTROY :
            PostQuitMessage(0);
            return 0;

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

Avec la contribution de nico-pyright(c) pour la relecture.


À vos PC.

CGi

Sommaire

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

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 © 2013 CGi. 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.