Freigeben über


Änderungen am Programmiermodell

In den folgenden Abschnitten werden verschiedene Möglichkeiten beschrieben, wie sich die Programmierung mit Windows GDI+ von der Programmierung mit der Windows-Grafikgeräteschnittstelle (GDI) unterscheidet.

Gerätekontexte, Handles und Grafikobjekte

Wenn Sie Programme mit GDI geschrieben haben (die Grafikgeräteschnittstelle, die in früheren Versionen von Windows enthalten ist), sind Sie mit der Idee eines Gerätekontexts (DC) vertraut. Ein Gerätekontext ist eine von Windows verwendete Struktur zum Speichern von Informationen zu den Funktionen eines bestimmten Anzeigegeräts und von Attributen, die angeben, wie Elemente auf diesem Gerät dargestellt werden. Ein Gerätekontext für eine Videoanzeige ist auch einem bestimmten Fenster auf dem Bildschirm zugeordnet. Zuerst erhalten Sie einen Handle für einen Gerätekontext (HDC) und übergeben diesen Handle dann als Argument an GDI-Funktionen, die die Zeichnung tatsächlich durchführen. Außerdem übergeben Sie das Handle als Argument an GDI-Funktionen, die die Attribute des Gerätekontexts abrufen oder festlegen.

Wenn Sie GDI+ verwenden, müssen Sie sich nicht so sehr um Handles und Gerätekontexte kümmern wie bei der Verwendung von GDI. Sie erstellen einfach ein Graphics-Objekt und rufen dann seine Methoden im vertrauten objektorientierten Stil auf – myGraphicsObject.DrawLine(parameters). Das Graphics-Objekt befindet sich im Kern von GDI+ genau wie der Gerätekontext im Kern von GDI. Der Gerätekontext und das Graphics-Objekt spielen ähnliche Rollen, es gibt jedoch einige grundlegende Unterschiede zwischen dem mit Gerätekontexten verwendeten handle-basierten Programmiermodell (GDI) und dem mit Graphics-Objekten (GDI+) verwendeten objektorientierten Modell.

Das Graphics-Objekt ist wie der Gerätekontext einem bestimmten Fenster auf dem Bildschirm zugeordnet und enthält Attribute (z. B. Glättungsmodus und Textrenderinghinweise), die angeben, wie Elemente gezeichnet werden sollen. Das Graphics-Objekt ist jedoch nicht an einen Stift, Pinsel, Pfad, ein Bild oder eine Schriftart als Gerätekontext gebunden. Um beispielsweise in GDI einen Gerätekontext zum Zeichnen einer Linie verwenden zu können, müssen Sie SelectObject aufrufen, um ein Stiftobjekt dem Gerätekontext zuzuordnen. Dies wird als Auswahl des Stifts im Gerätekontext bezeichnet. Alle Linien, die im Gerätekontext gezeichnet werden, verwenden diesen Stift, bis Sie einen anderen Stift auswählen. Mit GDI+ übergeben Sie ein Stift-Objekt als Argument an die DrawLine-Methode der Graphics-Klasse. Sie können in jeder Reihe von DrawLine-Aufrufen ein anderes Stift-Objekt verwenden, ohne ein bestimmtes Stift-Objekt einem Graphics-Objekt zuordnen zu müssen.

Zwei Möglichkeiten zum Zeichnen einer Linie

In den folgenden beiden Beispielen wird jeweils eine rote Linie der Breite 3 von der Position (20, 10) bis zur Position (200,100) gezeichnet. Im ersten Beispiel wird GDI aufgerufen, und das zweite ruft GDI+ über die C++-Klassenschnittstelle auf.

Zeichnen einer Linie mit GDI

Zum Zeichnen einer Linie mit GDI benötigen Sie zwei Objekte: einen Gerätekontext und einen Stift. Sie erhalten ein Handle zu einem Gerätekontext, indem Sie BeginPaint und ein Handle für einen Stift aufrufen, indem Sie CreatePen aufrufen. Als Nächstes rufen Sie SelectObject auf, um den Stift im Gerätekontext auszuwählen. Sie legen die Stiftposition auf (20, 10) fest, indem Sie MoveToEx aufrufen. Zeichnen Sie dann eine Linie von dieser Stiftposition zu (200, 100), indem Sie LineTo aufrufen. Beachten Sie, dass MoveToEx und LineTo beide hdc als Argument empfangen.

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

Zeichnen einer Linie mit GDI+ und der C++-Klassenschnittstelle

Zum Zeichnen einer Linie mit GDI+ und der C++-Klassenschnittstelle benötigen Sie ein Graphics-Objekt und ein Stift-Objekt. Beachten Sie, dass Sie Windows nicht nach Handles für diese Objekte fragen. Stattdessen verwenden Sie Konstruktoren, um eine Instanz der Graphics-Klasse (ein Graphics-Objekt) und eine Instanz der Stift-Klasse (ein Stift-Objekt) zu erstellen. Das Zeichnen einer Linie umfasst das Aufrufen der Graphics::DrawLine-Methode der Graphics-Klasse. Der erste Parameter der Graphics::D rawLine-Methode ist ein Zeiger auf Ihr Stift-Objekt. Dies ist ein einfacheres und flexibleres Schema als die Auswahl eines Stifts in einem Gerätekontext, wie im vorhergehenden GDI-Beispiel gezeigt.

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

Stifte, Pinsel, Pfade, Bilder und Schriftarten als Parameter

In den vorherigen Beispielen wird gezeigt, dass Stift-Objekte getrennt vom Graphics-Objekt, das die Zeichnungsmethode bereitstellt, erstellt und verwaltet werden können. Pinsel-, GraphicsPath-, Bild- und Schriftart-Objekte können auch separat vom Graphics-Objekt erstellt und verwaltet werden. Viele der Zeichnungsmethoden, die von der Graphics-Klasse bereitgestellt werden, erhalten ein Pinsel-, GraphicsPath-, Bild- oder Schriftart-Objekt als Argument. Die Adresse eines Brush-Objekts wird als Argument an die FillRectangle-Methode übergeben, und die Adresse eines GraphicsPath-Objekts wird als Argument an die Graphics::DrawPath-Methode übergeben. Ebenso werden Adressen von Bild- und Schriftart-Objekten an die DrawImage- und DrawString-Methoden übergeben. Dies steht im Gegensatz zu GDI, wo Sie einen Pinsel, Pfad, ein Bild oder eine Schriftart im Gerätekontext auswählen und dann einen Handle an den Gerätekontext als Argument an eine Zeichenfunktion übergeben.

Methodenüberladung

Viele der GDI+-Methoden sind überladen; d. h., mehrere Methoden verwenden denselben Namen, weisen jedoch unterschiedliche Parameterlisten auf. Die DrawLine-Methode der Graphics-Klasse gibt es in den folgenden Formen:

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

Alle vier der obigen DrawLine-Variationen erhalten einen Zeiger auf ein Stift-Objekt, die Koordinaten des Ausgangspunkts und die Koordinaten des Endpunkts. Die ersten beiden Varianten erhalten die Koordinaten als Gleitkommazahlen und die letzten beiden Varianten erhalten die Koordinaten als Ganzzahlen. Die ersten und dritten Varianten erhalten die Koordinaten als Liste mit vier separaten Zahlen, während die zweite und vierte Variante die Koordinaten als Punkt-Objekt (oder PointF) empfangen.

Keine aktuelle Position mehr

Beachten Sie, dass in den zuvor gezeigten DrawLine-Methoden sowohl der Startpunkt als auch der Endpunkt der Linie als Argumente empfangen werden. Dies ist eine Abweichung vom GDI-Schema, bei dem Sie MoveToEx aufrufen, um die aktuelle Stiftposition festzulegen, gefolgt von LineTo, um eine Linie zu zeichnen, die bei (x1, y1) beginnt und bei (x2, y2) endet. GDI+ hat als Ganzes das Konzept der aktuellen Position aufgegeben.

Separate Methoden für Zeichnen und Ausfüllen

GDI+ ist flexibler als GDI, wenn es darum geht, die Konturen zu zeichnen und die Innenräume von Formen wie Rechtecke zu füllen. GDI verfügt über eine Rechteckfunktion, die die Kontur zeichnet und das Innere eines Rechtecks in einem Schritt ausfüllt. Die Kontur wird mit dem aktuell ausgewählten Stift gezeichnet, und der Innenbereich wird mit dem aktuell ausgewählten Pinsel gefüllt.

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+ verfügt über separate Methoden zum Zeichnen der Kontur und Ausfüllen des Innenbereichs eines Rechtecks. Die DrawRectangle-Methode der Graphics-Klasse weist die Adresse eines Stift-Objekts als einen seiner Parameter auf, und die FillRectangle-Methode hat die Adresse eines Pinsel-Objekts als einen seiner Parameter.

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

Beachten Sie, dass die FillRectangle- und DrawRectangle-Methoden in GDI+ Argumente empfangen, die den linken Rand, die Oberseite, die Breite und die Höhe des Rechtecks angeben. Dies steht im Gegensatz zur GDI-Funktion Rechteck, die Argumente verwendet, die den linken und rechten Rand sowie die Ober- und Unterseite des Rechtecks angeben. Beachten Sie außerdem, dass der Konstruktor für die Farb-Klasse in GDI+ vier Parameter aufweist. Die letzten drei Parameter sind die üblichen Rot-, Grün- und Blauwerte; der erste Parameter ist der Alphawert, der angibt, inwieweit die gezeichnete Farbe mit der Hintergrundfarbe gemischt wird.

Erstellen von Regionen

GDI bietet mehrere Funktionen zum Erstellen von Regionen: CreateRectRgn, CreateEllpticRgn, CreateRoundRectRgn, CreatePolygonRgn und CreatePolyPolygonRgn. Möglicherweise erwarten Sie, dass die Regions-Klasse in GDI+ analoge Konstruktoren enthält, die Rechtecke, Auslassungspunkte, abgerundete Rechtecke und Polygone als Argumente verwenden, das ist jedoch nicht der Fall. Die Regions-Klasse in GDI+ stellt einen Konstruktor bereit, der einen Rect-Objektverweis und einen anderen Konstruktor empfängt, der die Adresse eines GraphicsPath-Objekts empfängt. Wenn Sie eine Region auf der Grundlage einer Ellipse, eines abgerundeten Rechtecks oder eines Polygons konstruieren möchten, können Sie dies ganz einfach tun, indem Sie ein GraphicsPath-Objekt (das beispielsweise ein Auslassungszeichen enthält) erstellen und dann die Adresse dieses GraphicsPath-Objekts an einen Regions-Konstruktor übergeben.

GDI+ erleichtert das Erstellen komplexer Bereiche durch Kombinieren von Formen und Pfaden. Die Regions-Klasse verfügt über Union- und Intersect-Methoden, mit denen Sie eine vorhandene Region mit einem Pfad oder einer anderen Region erweitern können. Ein nettes Feature des GDI+-Schemas ist, dass ein GraphicsPath-Objekt nicht zerstört wird, wenn es als Argument an einen Regions-Konstruktor übergeben wird. In GDI können Sie einen Pfad in eine Region mit der PathToRegion-Funktion konvertieren, aber der Pfad wird im Prozess zerstört. Außerdem wird ein GraphicsPath-Objekt nicht zerstört, wenn seine Adresse als Argument an eine Union- oder Intersect-Methode übergeben wird, sodass Sie einen bestimmten Pfad als Baustein für mehrere separate Bereiche verwenden können. Dies wird im folgenden Beispiel gezeigt. Angenommen, onePath ist ein Zeiger auf ein GraphicsPath-Objekt (einfach oder komplex), das bereits initialisiert wurde.

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