Graphisme
Afficher un point à l'écran: SetPixel() ou SetPixelV()
COLORREF SetPixel(
HDC hdc, // handle contexte de périphérique
int X, // coordonnée x du pixel
int Y, // coordonnée y du pixel
COLORREF crColor // couleur du pixel
);
Avec : hdc qui est toujours le handle sur le contexte priphérique.
X et Y : les coordonnées en pixel du point à afficher.
crColor : La couleur du pixel de type COLORREF (utilisez la macro RGB pour définir la couleur).
En sortie, la fonction retourne la couleur réellement utilisée par Windows. En effet, si la couleur demandée n'est pas diponible dans la palette, Windows va utiliser la couleur la plus proche.
ou la fonction retourne 1 si erreur. Il est alors préférable d'utiliser GetLastError() qui doit retourner ERROR_INVALID_PARAMETER si une erreur existe réellement.
BOOL SetPixelV(
HDC hdc, // handle contexte de périphérique
int X, // coordonnée x du pixel
int Y, // coordonnée y du pixel
COLORREF crColor // couleur du pixel
);
Cette fonction est identique à la précedente. la différence étant qu'elle ne retourne pas la couleur réellement utilisée, mais 0 si une erreur vient de se produire.
Voici un petit exemple pour illustrer cela: Affichage de 10000 points dans la fenêtre de manière aléatoire et de couleurs aléatoires elles aussi.
En
principe, ce code reste rapide pour afficher tous ces points à l'écran.
Lire la couleur d'un point:
Il est possible que vous ayez besoin de connaître la couleur d'un pixel sur une coordonnée. Utilisez la fonction GetPixel:
COLORREF GetPixel(
HDC hdc, // handle contexte de périphérique
int X, // coordonnée x à lire
int Y // coordonnée y à lire
);
Stylo et pinceau/Sélection ou déselection d'un objet graphique:
Avant d'attaquer les autres fonctions graphiques, parlons un peu des outils utilisés par Windows pour permettre de dessiner ces figures:
Pour dessiner, il faut: un stylo (pen) pour faire le contour d'une figure, et un pinceau (brush) pour remplir la figure. Il faut donc définir tout cela avant de faire une figure:
Le stylo:
Windows propose des stylos par défaut:
Le stylo initial se nomme BLACK_PEN (noir). Il trace des traits pleins, d'une largeur de 1 pixel et de couleur noire.
Il y a aussi le WHITE_PEN qui est identique au BLACK_PEN, mais de couleur blanche. Et enfin, le NULL_PAINT de couleur transparente.
Pour utiliser ces stylos, il faut utiliser la fonction GetStockObject:
qui retournera un handle de type HPEN ou NULL si erreur.
HPEN hpen;
hpen = GetStockObject(WHITE_PEN); // Définir un handle pour l'utilisation du stylo blanc
Puis la fonction SelectObject pour utiliser le tout nouveau stylo lors des prochaines opérations graphiques.
HGDIOBJ SelectObject(
HDC hdc, // handle sur device contextDC
HGDIOBJ hgdiobj // handle de l'objet à sélectionner
);
En sortie, la fonction retourne le handle de l'objet précédement utilisé. Bien utile pour repositionner le stylo précédent...
hpenancien = SelectObject(hdc, hpen);
En principe, lorsque l'objet n'est plus utilisé, vous utilisez la commande DeleteObject() pour détruire cet objet. Mais comme il s'agit d'un stylo du système, cette opération ne sera pas nécessaire. Car Windows ne libèrera de toute façon pas les ressources, d'autres applications peuvent en avoir besoin !
La fonction retourne 0 si problème.
Après les tylos par défaut, il est possible de s'en créer
un soit même:
HPEN CreatePen(
int fnPenStyle, // Style du stylo
int nWidth, // Largeur du stylo
COLORREF crColor // Couleur
du stylo (utilisez la macro RGB
pour définir la couleur).
);
Avec les tyles suivant:
Style | Affichage |
PS_SOLID | ![]() |
PS_DASH | ![]() |
PS_DOT | ![]() |
PS_DASHDOT | ![]() |
PS_DASHDOTDOT | ![]() |
PS_NULL | |
PS_INSIDEFRAME | ![]() |
La fonction retournera un handle sur l'objet ou NULL si erreur.
Pour ne modifier que la couleur du stylo (utilisez la macro RGB pour définir la couleur):
COLORREF SetDCPenColor(
HDC hdc,
COLORREF crColor
);
Pour lire la couleur:
COLORREF GetDCPenColor(
HDC hdc // handle du DC
);
Création d'un stylo de manière indirecte:
Création d'un pinceau en déclarant une structure de type LOGPEN
(Logical pen) et en utilisant CreatePenIndirect.
LOGPEN contient trois champs : le style du stylo, l'épaisseur et enfin
la couleur
(macro RGB...).
typedef struct tagLOGPEN {
UINT lopnStyle;
POINT lopnWidth;
COLORREF lopnColor;
} LOGPEN, *PLOGPEN;
HPEN CreatePenIndirect(
CONST LOGPEN *lplgpn
);
Il est possible d'utiliser des pinceaux par défaut:
Valeur | Description |
BLACK_BRUSH | Pinceau noir |
DKGRAY_BRUSH | Pinceau gris foncé |
DC_BRUSH | Remplissage en blanc par défaut, la couleur est modifiable par SetDCBrushColor() |
GRAY_BRUSH | Pinceau gris |
HOLLOW_BRUSH | idem que NULL_BRUSH |
LTGRAY_BRUSH | Pinceau gris clair |
NULL_BRUSH | Pas de pinceau |
WHITE_BRUSH | Pinceau blanc |
Vous utiliserez là aussi GetStockObject qui donnera en retour un handle de type HBRUSH ou NULL si erreur.
Puis la fonction SelectObject pour utiliser notre pinceau dans les prochaines opération graphique.
Pour les mêmes
raisons que le stylo, le DeleteObject ne sera pas nécessaire.
Il sera possible de définir un pinceau avec un remplissage total de la couleur (macro RGB...) que vous souhaitez:
HBRUSH CreateSolidBrush(
COLORREF crColor // couleur du pinceau
);
ou un pinceau avec un remplissage hachuré de la couleur (macro RGB...) que vous souhaitez:
HBRUSH CreateHatchBrush(
int fnStyle, // style de hachure
COLORREF clrref // couleur en avant plan
);
Style | Affichage |
HS_BDIAGONAL | ![]() |
HS_CROSS | ![]() |
HS_DIAGCROSS | ![]() |
HS_FDIAGONAL | ![]() |
HS_HORIZONTAL | ![]() |
HS_VERTICAL | ![]() |
Il est enfin possible de définir son propre pinceau grâce à la fonction CreatePatternBrush() à partir d'un bitmap, mais cette fonction sera étudiée après le chapitre sur les bitmaps (Voir ici, complément sur le pinceau). Voir aussi GetSysColor() et GetSysColorBrush().
Création indirect d'un pinceau:
HBRUSH CreateBrushIndirect(
CONST LOGBRUSH *lplb
);
Avec LOGBRUSH
typedef struct tagLOGBRUSH {
UINT lbStyle;
COLORREF lbColor;
LONG lbHatch;
} LOGBRUSH, *PLOGBRUSH;
Pour lire les informations d'un stylo:
GetObject (hPen, sizeof (LOGPEN), (LPSTR) &logpen)
Les autres fonctions de définissions des attributs:
Il est possible aussi de définir la couleur de fond avec la fonction SetBkColor() ou le mode à utiliser avec le fond avec SetBkMode(). Ces fonctions ont déjà été étudiée dans le chapitre sur les textes
Dessiner une droite
Pour tracer une droite il faut définir les coordonnées de départ:
MoveToEx () va permettre de définir ces coordonnées.
BOOL MoveToEx(
HDC hdc, // Toujours le handle sur le contexte périphérique
int X, // Nouvelle position en X
int Y, // Nouvelle position en Y
LPPOINT lpPoint // Pointeur sur une structure de type POINT
qui recevra en sortie les coordonnées précédentes. Il est
possible de passer NULL si ces valeurs ne vous intéressent pas.
);
Puis définir les coordonnées d'arrivées:
BOOL LineTo(
HDC hdc,
int nXEnd,
int nYEnd
);
avec nXEnd et nYEnd les coordonnées pour terminer le segment de droite. Cette fonction retourne 0 si erreur.

Le dernier point
de la ligne n'est jamais dessiné. La raison est plutôt liée
aux tables traçantes:Si vous dessiner une ligne puis une autre en repartant
du dernier point de la ligne précédente, ce point serait tracé
2 fois, d'où un risque de bavure...
La position courante
est à (0,0) au lancement du programme. Donc si vous faite un LineTo()
avant MoveToEx, votre ligne démarrera de (0,0).
Enfin, vous pouvez connaître la position courante grâce à la fonction:
BOOL GetCurrentPositionEx(
HDC hdc, // ...
LPPOINT lpPoint // Pointeur sur une structure de type POINT
contenant en sortie la position courante
);
Voici deux exemples pour dessiner des lignes:
Le premier trace 1000 segments de droites n'importe où dans une fenêtre:
Le second affiche un dégradé de rouge:
D'autres fonctions, passées rapidement, il n'y a rien de bien compliqué:
Dessiner plusieurs lignes
BOOL Polyline(
HDC hdc,
CONST POINT *lppt, // Pointeur sur un tableau de coordonnées
int cPoints // Nombre de point à dessiner doit être supérieur
ou égal à 2
);
Ne met pas à jour la position courante.
BOOL PolylineTo(
HDC hdc,
CONST POINT *lppt, // Pointeur sur un tableau de coordonnées
int cPoints // Nombre de point à dessiner doit être supérieur
ou égal à 2
);
Cette fonction va mettre à jour la position courante comme LineTo.
Le rectangle
BOOL Rectangle(
HDC hdc, // Devinez ?
int nLeftRect, // coordonnée en x du coin supérieur gauche
int nTopRect, // coordonnée en y du coin supérieur gauche
int nRightRect, // coordonnée en x du coin inférieur droit
int nBottomRect // coordonnée en y du coin inférieur droit
);
0 si problème
Rectangle avec coins arrondis
BOOL RoundRect(
HDC hdc, // Devinez ?
int nLeftRect, // coordonnée en x du coin supérieur gauche
int nTopRect, // coordonnée en y du coin supérieur gauche
int nRightRect, // coordonnée en x du coin inférieur droit
int nBottomRect // coordonnée en y du coin inférieur droit
int nWidth, // largeur de l'ellipse
int nHeight // hauteur de l'ellipse
);
Ellipse
Vous passez les coordonnées d'un rectangle contenant l'ellipse.
BOOL Ellipse(
HDC hdc, // Devinez ?
int nLeftRect, // coordonnée en x du coin supérieur gauche
int nTopRect, // coordonnée en y du coin supérieur gauche
int nRightRect, // coordonnée en x du coin inférieur droit
int nBottomRect // coordonnée en y du coin inférieur droit
);
Retourne 0 si erreur.
Cercle
Utilisez la fonction Ellipse(). Remarque évidente, mais bon : Pour faire un cercle, le rectangle est un rectangle particulier: un carré !!!
Un arc d'ellipse
BOOL Arc(
HDC hdc, // Devinez ?
int nLeftRect, // coordonnée en x du coin supérieur gauche
int nTopRect, // coordonnée en y du coin supérieur gauche
int nRightRect, // coordonnée en x du coin inférieur droit
int nBottomRect // coordonnée en y du coin inférieur droit
int nXStartArc, // coordonnée x départ de l'arc
int nYStartArc, // coordonnée y départ de l'arc
int nXEndArc, // coordonnée x fin de l'arc
int nYEndArc // coordonnée y fin de l'arc
);
De même, il y a la fonction Chord qui trace un arc et relie les deux points extrèmes entre eux.
La fonction Pie qui elle aussi trace un arc, et dessine des segments entre les points extrèmes de l'arc et le centre.
Pour ces fonctions de traçage d'une ellipse, il peut-être intéressant de changer le repère en mode ISOTROPIC (cf. le chapitre sur le repère)
Encore des fonctions, en vrac
int FillRect(
HDC hDC, // handle contexte périphérique
CONST RECT *lprc, // coordonnée du rectandle
HBRUSH hbr // handle sur un pinceau
);
Attention, cette fonction va dessiner un rectangle avec le pinceau mais s'arrête juste avant les coordonées finales du rectangle.
lprc est un pointeur sur une structure de type RECT qui recevra les coordonnées formattées en sortie.
Pour dessiner une bordure autour d'un rectangle:
int FrameRect(
HDC hDC, // handle sur DC
CONST RECT *lprc, // rectangle (structure
RECT)
HBRUSH hbr // handle pinceau
);
Pour inverser (opération NON) un rectangle:
BOOL InvertRect(
HDC hDC, // handle sur DC
CONST RECT *lprc // pointeur sur coordonnées rectangle (structure
RECT)
);
Il y a aussi PolyPolyLine, Polygon et PolyPolygon que je n'ai jamais essayé, mais les noms semblent assez compréhensibles.
Exemple:
Voici un exemple utilisant les fonctions les plus courantes: