Changements dans le modèle de programmation

les sections suivantes décrivent différentes façons de programmer avec Windows GDI+ est différente de la programmation avec les Graphics Device Interface de Windows (GDI).

Contextes de périphérique, Handles et objets graphiques

si vous avez écrit des programmes à l’aide de GDI (l’interface de périphérique graphique incluse dans les versions précédentes de Windows), vous êtes familiarisé avec l’idée d’un contexte de périphérique (DC). un contexte de périphérique est une structure utilisée par Windows pour stocker des informations sur les fonctionnalités d’un périphérique d’affichage particulier et les attributs qui spécifient la façon dont les éléments sont dessinés sur cet appareil. Un contexte de périphérique pour un affichage vidéo est également associé à une fenêtre particulière sur l’écran. Tout d’abord, vous obtenez un handle vers un contexte de périphérique (HDC), puis vous transmettez ce handle comme argument aux fonctions GDI qui effectuent en fait le dessin. Vous transmettez également le handle comme argument aux fonctions GDI qui obtiennent ou définissent les attributs du contexte de périphérique.

lorsque vous utilisez GDI+, vous n’avez pas à vous soucier des handles et des contextes de périphérique, comme vous le feriez lorsque vous utilisez GDI. Il vous suffit de créer un objet Graphics , puis d’appeler ses méthodes dans le style orienté objet familier, MyGraphicsObject. DrawLine (paramètres). l’objet graphics est au cœur de GDI+ tout comme le contexte de périphérique est au cœur de GDI. Le contexte de périphérique et l’objet Graphics jouent des rôles similaires, mais il existe des différences fondamentales entre le modèle de programmation basé sur les descripteurs et les contextes de périphérique (GDI) et le modèle orienté objet utilisé avec les objets graphics (GDI+).

L’objet Graphics , comme le contexte de périphérique, est associé à une fenêtre particulière à l’écran et contient des attributs (par exemple, le mode de lissage et l’indicateur de rendu de texte) qui spécifient la façon dont les éléments doivent être dessinés. Toutefois, l’objet Graphics n’est pas lié à un stylet, un pinceau, un tracé, une image ou une police comme contexte de périphérique. Par exemple, dans GDI, avant de pouvoir utiliser un contexte de périphérique pour dessiner une ligne, vous devez appeler SelectObject pour associer un objet Pen au contexte de périphérique. On parle alors de sélectionner le stylet dans le contexte de l’appareil. Toutes les lignes dessinées dans le contexte de périphérique utilisent ce stylet jusqu’à ce que vous sélectionnez un autre stylet. avec GDI+, vous transmettez un objet Pen en tant qu’argument à la méthode DrawLine de la classe graphics . Vous pouvez utiliser un objet Pen différent dans chacune d’une série d’appels DrawLine sans avoir à associer un objet Pen donné à un objet Graphics .

Deux façons de dessiner une ligne

Les deux exemples suivants dessinent chacun une ligne rouge de largeur 3 à partir de l’emplacement (20, 10) à l’emplacement (200 100). le premier exemple appelle GDI et le deuxième appel GDI+ via l’interface de la classe C++.

Dessin d’une ligne avec GDI

Pour dessiner une ligne avec GDI, vous avez besoin de deux objets : un contexte de périphérique et un stylet. Vous pouvez obtenir un handle vers un contexte de périphérique en appelant BeginPaintet un handle à un stylet en appelant CreatePen. Ensuite, vous appelez SelectObject pour sélectionner le stylet dans le contexte de l’appareil. Vous définissez la position du stylet sur (20, 10) en appelant MoveToEx , puis dessinez une ligne à partir de cette position de stylet sur (200, 100) en appelant LineTo. Notez que MoveToEx et LineTo reçoivent tous deux HDC comme argument.

HDC          hdc;
PAINTSTRUCT  ps;
HPEN         hPen;
HPEN         hPenOld;
hdc = BeginPaint(hWnd, &ps);
   hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
   hPenOld = (HPEN)SelectObject(hdc, hPen);
   MoveToEx(hdc, 20, 10, NULL);
   LineTo(hdc, 200, 100);
   SelectObject(hdc, hPenOld);
   DeleteObject(hPen);
EndPaint(hWnd, &ps);

dessin d’une ligne avec GDI+ et l’interface de classe C++

pour dessiner une ligne avec GDI+ et l’interface de classe C++, vous avez besoin d’un objet graphics et d’un objet Pen . notez que vous ne demandez pas Windows pour les descripteurs de ces objets. Au lieu de cela, vous utilisez des constructeurs pour créer une instance de la classe Graphics (un objet Graphics ) et une instance de la classe Pen (un objet Pen ). Le dessin d’une ligne implique l’appel de la méthode Graphics ::D rawline de la classe Graphics . Le premier paramètre de la méthode Graphics ::D rawline est un pointeur vers votre objet Pen . Il s’agit d’un schéma plus simple et plus souple que la sélection d’un stylet dans un contexte de périphérique, comme indiqué dans l’exemple GDI précédent.

HDC          hdc;
PAINTSTRUCT  ps;
Pen*         myPen;
Graphics*    myGraphics;
hdc = BeginPaint(hWnd, &ps);
   myPen = new Pen(Color(255, 255, 0, 0), 3);
   myGraphics = new Graphics(hdc);
   myGraphics->DrawLine(myPen, 20, 10, 200, 100);
   delete myGraphics;
   delete myPen;
EndPaint(hWnd, &ps);

Stylets, pinceaux, tracés, images et polices en tant que paramètres

Les exemples précédents montrent que les objets Pen peuvent être créés et gérés séparément de l’objet Graphics , qui fournit les méthodes de dessin. Les objets Brush, GraphicsPath, imageet font peuvent également être créés et gérés séparément de l’objet Graphics . La plupart des méthodes de dessin fournies par la classe Graphics reçoivent un objet Brush, GraphicsPath, image ou font comme argument. Par exemple, l’adresse d’un objet Brush est passée comme argument à la méthode FillRectangle , et l’adresse d’un objet GraphicsPath est passée comme argument à la méthode Graphics ::D rawpath . De même, les adresses des objets image et font sont passées aux méthodes DrawImage et DrawString . Contrairement à GDI, vous pouvez sélectionner un pinceau, un tracé, une image ou une police dans le contexte de périphérique, puis passer un handle au contexte de périphérique en tant qu’argument d’une fonction de dessin.

Surcharge de méthode

la plupart des méthodes GDI+ sont surchargées ; autrement dit, plusieurs méthodes partagent le même nom, mais ont des listes de paramètres différentes. Par exemple, la méthode DrawLine de la classe Graphics est présente sous la forme suivante :

Status DrawLine(IN const Pen* pen,
                IN REAL x1,
                IN REAL y1,
                IN REAL x2,
                IN REAL y2);
Status DrawLine(IN const Pen* pen,
                IN const PointF& pt1,
                IN const PointF& pt2);
Status DrawLine(IN const Pen* pen,
                IN INT x1,
                IN INT y1,
                IN INT x2,
                IN INT y2);
    
Status DrawLine(IN const Pen* pen,
                IN const Point& pt1,
                IN const Point& pt2);

Les quatre variations DrawLine ci-dessus reçoivent un pointeur vers un objet Pen , les coordonnées du point de départ et les coordonnées du point de fin. Les deux premières variations reçoivent les coordonnées sous forme de nombres à virgule flottante, et les deux dernières variations reçoivent les coordonnées sous forme d’entiers. Les première et troisième variations reçoivent les coordonnées sous la forme d’une liste de quatre nombres distincts, tandis que les deuxième et quatrième versions reçoivent les coordonnées sous la forme d’un couple d’objets point (ou PointF).

Plus de position actuelle

Notez que dans les méthodes DrawLine indiquées précédemment, le point de départ et le point de fin de la ligne sont reçus comme arguments. Il s’agit d’un écart par rapport au schéma GDI dans lequel vous appelez MoveToEx pour définir la position actuelle du stylet suivie de LineTo pour dessiner une ligne commençant à (x1, Y1) et se terminant à (x2, Y2). GDI+ dans son ensemble a abandonné la notion de position actuelle.

Méthodes distinctes pour dessiner et remplir

GDI+ est plus flexible que GDI lorsqu’il s’agit de dessiner les plans et de remplir l’intérieur des formes comme les rectangles. GDI a une fonction rectangle qui dessine le contour et remplit l’intérieur d’un rectangle tout en une seule étape. Le contour est dessiné avec le stylet actuellement sélectionné, et l’intérieur est rempli avec le pinceau actuellement sélectionné.

hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
SelectObject(hdc, hBrush);
SelectObject(hdc, hPen);
Rectangle(hdc, 100, 50, 200, 80);

GDI+ a des méthodes distinctes pour dessiner le contour et remplir l’intérieur d’un rectangle. La méthode DrawRectangle de la classe Graphics a l’adresse d’un objet Pen comme l’un de ses paramètres, et la méthode FillRectangle a l’adresse d’un objet Brush comme l’un de ses paramètres.

HatchBrush* myHatchBrush = new HatchBrush(
   HatchStyleCross,
   Color(255, 0, 255, 0),
   Color(255, 0, 0, 255));
Pen* myPen = new Pen(Color(255, 255, 0, 0), 3);
myGraphics.FillRectangle(myHatchBrush, 100, 50, 100, 30);
myGraphics.DrawRectangle(myPen, 100, 50, 100, 30);

notez que les méthodes FillRectangle et DrawRectangle dans GDI+ recevoir des arguments qui spécifient le bord gauche, la largeur et la hauteur du rectangle. Cela diffère de la fonctionrectangle GDI, qui accepte les arguments qui spécifient le bord gauche du rectangle, le bord droit, le haut et le bas. notez également que le constructeur de la classe Color dans GDI+ a quatre paramètres. Les trois derniers paramètres sont les valeurs de rouge, de vert et de bleu habituelles. le premier paramètre est la valeur alpha, qui spécifie dans quelle mesure la couleur dessinée est mélangée à la couleur d’arrière-plan.

Construction de régions

GDI fournit plusieurs fonctions pour la création de régions : CreateRectRgn, CreateEllpticRgn, CreateRoundRectRgn, CreatePolygonRgn et CreatePolyPolygonRgn. vous vous attendez peut-être à ce que la classe Region dans GDI+ ait des constructeurs analogues qui acceptent des rectangles, des ellipses, des rectangles arrondis et des polygones comme arguments, mais ce n’est pas le cas. la classe Region dans GDI+ fournit un constructeur qui reçoit une référence d’objet Rect et un autre constructeur qui reçoit l’adresse d’un objet GraphicsPath . Si vous souhaitez construire une région basée sur une ellipse, un rectangle arrondi ou un polygone, vous pouvez facilement le faire en créant un objet GraphicsPath (qui contient une ellipse, par exemple), puis en passant l’adresse de cet objet GraphicsPath à un constructeur Region .

GDI+ permet de créer facilement des zones complexes en combinant des formes et des tracés. La classe Region a des méthodes Union et Intersect que vous pouvez utiliser pour augmenter une région existante avec un chemin d’accès ou une autre région. une fonctionnalité intéressante du schéma de GDI+ est qu’un objet GraphicsPath n’est pas détruit lorsqu’il est passé comme argument à un constructeur Region . Dans GDI, vous pouvez convertir un chemin d’accès à une région avec la fonction PathToRegion , mais le chemin d’accès est détruit dans le processus. En outre, un objet GraphicsPath n’est pas détruit quand son adresse est passée comme argument à une méthode Union ou INTERSECT. vous pouvez donc utiliser un chemin d’accès donné comme bloc de construction pour plusieurs régions distinctes. Cela est illustré par l'exemple suivant. Supposons que onePath est un pointeur vers un objet GraphicsPath (simple ou complexe) qui a déjà été initialisé.

Region  region1(rect1);
Region  region2(rect2);
region1.Union(onePath);
region2.Intersect(onePath);