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