Developpez.com - C
X

Choisissez d'abord la catégorieensuite la rubrique :



API Windows en C

5 - Les contextes de périphériques.

Par CGi

Le 10 juin 2005




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ériques de sortie (Ecran, 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.



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.

    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;
            }

A 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 veux é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 :


Le message WM_PAINT :

A chaque fois qu'une fenêtre ou une partie de fenêtre à 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:

        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 du 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 à 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éfini de type (struct PAINTSTRUCT) comme paramètre afin d'y mémoriser des informations.

        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.

Code complet :

#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);
    }
}

A vos PC.

CGi

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



Sommaire



C/C++
  Les pointeurs du C/C++.   Les listes chaînées.             Liste simple.             Liste triée.             Liste double.   Les arbres.   Les tas.   Le C orienté objets ?

  1 - La fenêtre principale.   2 - Contrôles et messages.   3 - Les commandes.   4 - Dialogue std.   5 - Contexte de périph.   6 - Dessiner.   7 - Les ressources.   8 - Dialogue perso.   9 - Dialogue comm.   10 - Les accélérateurs.

Assembleur
  Assembleur sous Visual C++.

C++ BUILDER
  Trucs et astuces.   Composant.   TRichEdit.   TDrawGrid.   Application MDI.   TThread.   wxWidgets.   Style Win XP.

  Première application.   Construire un menu.   Dessiner.   Sisers, Timers...   Dialogues standards.   Dialogues perso.

DotNet
  Composant C# Builder.   Contrôle WinForm.   Application MDI.

Java
  Applet java.





Copyright 2002-2016 CGi - Tous droits réservés CGi. Toutes reproduction, utilisation ou diffusion de ce document par quelque moyen que ce soit autre que pour un usage personnel doit faire l'objet d'une autorisation écrite de la part de l'auteur, propriétaire des droits intellectuels.
Les codes sources de ce document sont fournis en l'état. L'utilisateur les utilise à ses risques et périls, sans garantie d'aucune sorte de la part de l'auteur. L'auteur n'est responsable d'aucun dommage subi par l'utilisateur pouvant résulter de l'utilisation ou de la distribution des codes sources de ce document.
De la même façon, l'auteur n'est en aucun cas responsable d'une quelconque perte de revenus ou de profits, ou de données, ou de tous dommages directs ou indirects, susceptibles de survenir du fait de l'utilisation des codes sources de ce document, quand bien même l'auteur aurait été averti de la possibilité de tels dommages. L'utilisation des codes sources de ce document vaut acceptation par l'utilisateur des termes de la licence ci-dessus.

Contacter le responsable de la rubrique C