共用方式為


程式設計模型中的變更

下列各節說明使用 Windows GDI+ 進行程式設計的方式,與使用 Windows Graphics Device Interface (GDI) 進行程序設計的方式不同。

裝置內容、句柄和圖形物件

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

當您使用 GDI+ 時,不需要像使用 GDI 時那樣關注句柄和裝置內容。 您只要建立 Graphics 對象,然後以熟悉的對象導向樣式叫用其方法, myGraphicsObject.DrawLine(parameters)。 Graphics 對象位於 GDI+ 的核心,就像裝置內容位於 GDI 的核心一樣。 裝置內容和 Graphics 物件扮演類似的角色,但與裝置內容搭配使用之句柄型程序設計模型(GDI)與圖形物件搭配使用的對象導向模型(GDI+)之間有一些基本差異。

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

繪製線條的兩種方式

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

使用 GDI 繪製線條

若要使用 GDI 繪製線條,您需要兩個物件:裝置內容和手寫筆。 您可以藉由呼叫 BeginPaint 取得裝置內容的句柄,以及呼叫 CreatePen 來取得手寫筆的句柄。 接下來,您會呼叫 SelectObject 來選取裝置內容中的手寫筆。 呼叫MoveToEx,然後將畫筆位置設定為 (20, 10),然後藉由呼叫LineTo,從該畫筆位置繪製線條到(200, 100)。 請注意,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 方法。 同樣地,Image 和 Font 物件的位址會傳遞至 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 方法則具有 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 方法會接收指定矩形左邊緣、上緣、寬度和高度的自變數。 這與 GDI Rectangle 函式形成鮮明對比,它會採用指定矩形左邊緣、右邊緣、上緣和底部的自變數。 另請注意,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 方法時,不會終結 GraphicsPath 物件,因此您可以使用指定的路徑做為數個不同區域的建置組塊。 下列範例會顯示這一點。 假設 onePath 是已初始化之 GraphicsPath 物件的指標(簡單或複雜)。

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