程式設計模型中的變更

下列各節說明使用 Windows GDI+ 進行程式設計的方式與使用 Windows 圖形裝置介面 (GDI) 的程式設計不同。

裝置內容、控制碼和繪圖物件

如果您已使用 GDI 撰寫程式, (舊版 Windows) 中包含的圖形裝置介面,您熟悉 DC (DC) 的裝置內容概念。 裝置內容是 Windows 用來儲存特定顯示裝置功能的相關資訊,以及指定如何在該裝置上繪製專案的屬性。 視訊顯示器的裝置內容也會與顯示器上的特定視窗相關聯。 首先,您會取得裝置內容的控制碼, (HDC) ,然後將該控制碼當做引數傳遞至實際執行繪圖的 GDI 函式。 您也會將控制碼當做引數傳遞至 GDI 函式,以取得或設定裝置內容的屬性。

當您使用 GDI+時,您不需要考慮使用 GDI 時的控制碼和裝置內容。 您只要建立 Graphics 物件,然後以熟悉的物件導向樣式叫用其方法, myGraphicsObject.DrawLine (參數) 。 Graphics物件位於 GDI+ 的核心,就像裝置內容位於 GDI 的核心一樣。 裝置內容和 Graphics 物件扮演類似的角色,但與裝置內容搭配使用之控制碼型程式設計模型有一些基本差異, (GDI) ,以及與 Graphics 物件搭配使用的物件導向模型, (GDI+) 。

圖形物件就像裝置內容一樣,會與螢幕上的特定視窗相關聯,並包含屬性 (例如平滑模式和文字轉譯提示,) 指定專案繪製方式。 不過, Graphics 物件不會系結至手寫筆、筆刷、路徑、影像或字型,因為裝置內容為 。 例如,在 GDI 中,您必須先呼叫 SelectObject ,才能使用裝置內容繪製線條,才能將手寫筆物件與裝置內容產生關聯。 這稱為在裝置內容中選取手寫筆。 在裝置內容中繪製的所有線條都會使用該畫筆,直到您選取不同的畫筆為止。 使用 GDI+,您會將Pen物件當做引數傳遞至Graphics類別的DrawLine方法。 您可以在每一系列 DrawLine 呼叫中使用不同的 Pen 物件,而不需要將指定的 Pen 物件與 Graphics 物件產生關聯。

繪製線條的兩種方式

下列兩個範例分別從位置 (20、10) 繪製寬度為 3 的紅色線條到位置 (200,100) 。 第一個範例會呼叫 GDI,第二個範例會透過 C++ 類別介面呼叫 GDI+ 。

使用 GDI 繪製線條

若要使用 GDI 繪製線條,您需要兩個物件:裝置內容和手寫筆。 您可以藉由呼叫 BeginPaint取得裝置內容的控制碼,以及呼叫 CreatePen來取得手寫筆的控制碼。 接下來,您會呼叫 SelectObject ,以將手寫筆選取到裝置內容中。 您可以藉由呼叫 MoveToEx 將畫筆位置設定為 (20,10) ,然後從該畫筆位置繪製線條,以 (200,100) 呼叫 LineTo。 請注意,MoveToEx 和 LineTo 都會以引數的形式接收 hdc

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

使用 GDI+ 和 C++ 類別介面繪製線條

若要使用 GDI+ 和 C++ 類別介面繪製線條,您需要 Graphics 物件和 Pen 物件。 請注意,您不會要求 Windows 處理這些物件的控制碼。 相反地,您可以使用建構函式建立Graphics類別的實例, (Graphics物件) ,而Pen類別的實例 (Pen物件) 。 繪製線條牽涉到呼叫Graphics 類別的 Graphics::D rawLine方法。 Graphics::D rawLine方法的第一個參數是Pen物件的指標。 這是比在裝置內容中選取手寫筆更簡單且更有彈性的配置,如上述 GDI 範例所示。

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

手寫筆、筆刷、路徑、影像和字型做為參數

上述範例顯示 Pen 物件可以與 Graphics 物件分開建立和維護,以提供繪圖方法。 筆刷GraphicsPathImageFont 物件也可以與 Graphics 物件分開建立和維護。 Graphics類別所提供的許多繪圖方法都會以引數的形式接收BrushGraphicsPathImageFont物件。 例如, Brush 物件的位址會當做引數傳遞至 FillRectangle 方法, 而 GraphicsPath 物件的位址會當做引數傳遞至 Graphics::D rawPath 方法。 同樣地, ImageFont 物件的位址會傳遞至 DrawImageDrawString 方法。 這與您選取筆刷、路徑、影像或字型到裝置內容中的 GDI 相反,然後將控制碼傳遞至裝置內容做為繪圖函式的引數。

方法多載

許多 GDI+ 方法都會多載;也就是說,數種方法共用相同的名稱,但有不同的參數清單。 例如,Graphics類別的DrawLine方法採用下列形式:

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

上述 DrawLine 變化的所有四個都會收到 Pen 物件的指標、起點的座標,以及結束點的座標。 前兩個變化會以浮點數的形式接收座標,最後兩個變化會以整數形式接收座標。 第一個和第三個變化會以四個不同的數位清單的形式接收座標,而第二個和第四個變化則會以 一對 Point (或 PointF) 物件的形式接收座標。

沒有其他目前的位置

請注意,在先前顯示的 DrawLine 方法中,行的起點和結束點都會以引數的形式接收。 這是從 GDI 配置開始,您會呼叫MoveToEx來設定目前的手寫筆位置,後面接著LineTo,以繪製從 (x1、y1) 開始的線條,並結束于 (x2y2) 。 GDI+ 整體已放棄目前位置的概念。

繪製和填滿的個別方法

GDI+ 在繪製外框和填滿矩形等圖形的內部時,比 GDI 更有彈性。 GDI 具有 Rectangle 函式,可繪製外框,並在一個步驟中填滿矩形的內部。 外框是使用目前選取的畫筆繪製,而內部會填入目前選取的筆刷。

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+ 有個別的方法可繪製外框並填滿矩形的內部。 Graphics類別的DrawRectangle方法具有Pen物件的位址做為其其中一個參數,而 FillRectangle方法的Address 是 Brush物件的位址做為其其中一個參數。

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

請注意,GDI+ 中的 FillRectangleDrawRectangle 方法會接收指定矩形左邊緣、上緣、寬度和高度的引數。 這與 GDIRectangle 函式相反,它會採用指定矩形左邊緣、右邊緣、上緣和底部的引數。 另請注意,GDI+ 中 Color 類別的建構函式有四個參數。 最後三個參數是一般紅色、綠色和藍色值;第一個參數是 Alpha 值,指定所繪製色彩與背景色彩混合的範圍。

建構區域

GDI 提供數個用於建立區域的函式:CreateRectRgn、CreateEllpticRgn、CreateRoundRectRgn、CreatePolygonRgn 和 CreatePolyPolygonRgn。 您可能會預期 GDI+ 中的 Region 類別具有類似的建構函式,其採用矩形、橢圓形、圓角矩形和多邊形做為引數,但這不是這種情況。 GDI+ 中的 Region 類別提供可接收 Rect 物件參考的建構函式,以及另一個接收 GraphicsPath 物件位址的建構函式。 如果您想要根據橢圓形、圓角矩形或多邊形建構區域,您可以建立包含橢圓形的 GraphicsPath 物件 (,例如) ,然後將該 GraphicsPath 物件的位址傳遞至 Region 建構函式,

GDI+ 可藉由結合圖形和路徑,輕鬆地形成複雜的區域。 Region類別具有UnionIntersect方法,可用來使用路徑或其他區域來增強現有區域。 GDI+ 配置的其中一個好功能是 當 GraphicsPath 物件當做引數傳遞至 Region 建構函式時不會終結。 在 GDI 中,您可以使用 PathToRegion 函式將路徑轉換成區域,但路徑會在程式中終結。 此外, 當 GraphicsPath 物件的位址當做引數傳遞至 Union 或 Intersect 方法時不會終結,因此您可以使用指定的路徑做為數個不同區域的建置組塊。 下列範例會顯示這一點。 假設 onePathGraphicsPath 物件的指標, (已經初始化的簡單或複雜) 。

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