GDI+ 是 Windows XP 時代引入的下一代圖形引擎,提供抗鋸齒、Alpha 混合、漸層、路徑、區域等現代繪圖功能,完全取代傳統 GDI 成為 .NET 時代 Windows 繪圖標準。本文系統整理 GDI+ 核心概念與 C++/CLI (或 Managed C++) 實戰代碼,涵蓋座標空間、畫筆、畫刷、漸層、矩陣變換、基本繪圖函數,並附圖示結果。
| 空間 | 描述 | 原點 | 單位 | 用途 |
| 世界座標 (World) | 應用程式邏輯座標,設備無關 | 自定義 | 自定義 (預設像素) | 繪圖邏輯、遊戲世界、CAD 模型 |
| 頁面座標 (Page) | 經映射模式轉換後的座標 | 可平移 | 可縮放 (SetPageUnit/Scale) | 列印預覽、多頁文檔佈局 |
| 設備座標 (Device) | 實際輸出設備像素座標 | 客戶區左上角 | 像素 | 滑鼠事件、命中測試、位圖像素操作 |
座標映射屬性與方法
using namespace Gdiplus;
Graphics graphics(dc.m_hDC); // 從 MFC CDC 獲取 HDC 建立 Graphics
// 1. 頁面單位 (預設 UnitPixel = 像素)
graphics.SetPageUnit(UnitMillimeter); // 每邏輯單位 = 1 公釐
// 可用值: UnitDisplay(1/75吋), UnitPixel, UnitPoint(1/72吋), UnitInch, UnitDocument(1/300吋), UnitMillimeter
// 2. 頁面縮放比例
graphics.SetPageScale(0.1f); // 0.1 倍,配合 Millimeter 即 0.1mm/單位
// 3. 平移變換 (移動原點)
graphics.TranslateTransform(100.0f, 50.0f); // 原點移至 (100,50) 頁面座標
// 組合效果:DrawRectangle(50,50,100,60) 在 Millimeter+Scale=0.1 下
// 實際繪製 5mm x 6mm 矩形,位置受 TranslateTransform 影響
單位換算速查
- 1 英吋 = 25.4 mm = 72 pt = 1440 twip = 96 像素 (預設 96 DPI) = 300 像素 (印表機 300 DPI)。
GetDeviceCaps(LOGPIXELSX/Y) 獲取當前設備 DPI,用於精確列印佈局。
二、畫筆 — 線條的藝術
基本構造
Pen pen(Color(255, 0, 0, 255), 3.0f); // ARGB 藍色,寬度 3
Pen pen(Color::Blue, 3.0f); // 預定義顏色
COLORREF cr = RGB(0,0,255);
Color color; color.SetFromCOLORREF(cr);
Pen pen(color, 3.0f); // 從 COLORREF 轉換
線型樣式
pen.SetDashStyle(DashStyleDash); // 虛線
pen.SetDashStyle(DashStyleDot); // 點線
pen.SetDashStyle(DashStyleDashDot); // 點劃線
pen.SetDashStyle(DashStyleDashDotDot); // 雙點劃線
pen.SetDashStyle(DashStyleCustom); // 自定義 (需配合 SetDashPattern)
自定義線型
REAL dashVals[4] = { 2, 2, 15, 2 }; // 短劃2、間隔2、長劃15、間隔2
pen.SetDashPattern(dashVals, 4);
graphics.DrawLine(&pen, 5, 20, 405, 200);
線帽樣式
pen.SetStartCap(LineCapFlat); // 起始平頭
pen.SetEndCap(LineCapSquare); // 終止方頭
pen.SetStartCap(LineCapRound); // 圓頭
pen.SetEndCap(LineCapRoundAnchor); // 圓錨頭
pen.SetStartCap(LineCapDiamondAnchor); // 鑽石錨頭
pen.SetEndCap(LineCapArrowAnchor); // 箭頭錨頭
三、畫刷與漸層 — 填充的藝術
純色與斜線畫刷
SolidBrush solid(Color(255, 255, 0, 0)); // 紅色實心
HatchBrush hatch(HatchStyleCross, // 十字斜線
Color(255, 0, 255, 0), // 前景綠
Color(255, 0, 0, 255)); // 背景藍
// 其他 HatchStyle: Horizontal, Vertical, ForwardDiagonal, BackwardDiagonal, DiagonalCross, 30Percent, SolidDiamond...
線性漸層畫刷
// 構造 1: 兩點定義矩形對角 + 兩顏色
LinearGradientBrush linGrBrush(
Point(300, 50), Point(500, 150), // 左上、右下
Color(255, 255, 0, 0), // 起始紅
Color(255, 0, 0, 255)); // 終止藍
// 構造 2: 矩形區域 + 角度
LinearGradientBrush linGrBrush2(
Rect(300, 50, 200, 100), // 區域
Color(255, 255, 0, 0), Color(255, 0, 0, 255),
45.0f, TRUE); // 45度順時針,可縮放角度
// 構造 3: 矩形區域 + 預定義模式
LinearGradientBrush linGrBrush3(
Rect(300, 50, 200, 100),
Color(255, 255, 0, 0), Color(255, 0, 0, 255),
LinearGradientModeForwardDiagonal); // 左下到右上
路徑漸層畫刷
GraphicsPath path;
path.AddEllipse(50, 50, 200, 100); // 橢圓路徑
PathGradientBrush pthGrBrush(&path); // 以路徑構造
pthGrBrush.SetCenterColor(Color(255, 0, 0, 255)); // 中心藍
Color colors[] = { Color(0, 0, 0, 255) }; // 周圍透明藍 (Alpha=0)
INT count = 1;
pthGrBrush.SetSurroundColors(colors, &count);
graphics.FillRectangle(&pthGrBrush, 50, 50, 200, 100); // 填充矩形 (實際受路徑裁剪)
紋理畫刷 (圖片填充)
Image image(L"image.jpg");
TextureBrush tBrush(&image);
Pen texturedPen(&tBrush, 10.0f); // 畫筆也可用紋理畫刷
graphics.DrawLine(&texturedPen, 25, 25, 325, 25);
tBrush.SetWrapMode(WrapModeTileFlipXY); // 鋪貼模式
graphics.FillRectangle(&tBrush, 25, 100, 300, 200);
四、圖形幾何變換 — 矩陣的力量
Matrix 類核心方法
Matrix matrix;
matrix.Translate(40, 0); // 平移
matrix.Rotate(30, MatrixOrderAppend); // 旋轉 30 度 (後置順序)
graphics.SetTransform(&matrix); // 套用變換
graphics.DrawEllipse(&pen, 0, 0, 100, 50); // 畫橢圓 (受變換影響)
矩陣數學本質 (3x3 齊次座標)
[x' y' 1] = [x y 1] * [m11 m12 0]
[m21 m22 0]
[dx dy 1]
dx, dy: 平移量
m11, m22: 縮放
m21, m12: 旋轉/錯切
常見變換矩陣速查
| 效果 | 矩陣參數 (m11,m12,m21,m22,dx,dy) |
| Y 軸鏡像 | -1, 0, 0, 1, dx, dy |
| X 軸鏡像 | 1, 0, 0, -1, dx, dy |
| 原點鏡像 | -1, 0, 0, -1, dx, dy |
| y=x 鏡像 | 0, 1, 1, 0, dx, dy |
| y=-x 鏡像 | 0, -1, -1, 0, dx, dy |
| 旋轉 θ | cosθ, sinθ, -sinθ, cosθ, dx, dy |
Graphics 內建變換方法 (無需手寫 Matrix)
graphics.RotateTransform(30); // 旋轉
graphics.ScaleTransform(2, 0.5); // 縮放
graphics.TranslateTransform(10,20); // 平移
// 順序影響結果:後調用的先套用 (預設 Prepend)
五、基本繪圖函數速查表
| 函數 | 功能 | 備註 |
| DrawLine | 直線 | 點對點、點陣列 |
| DrawArc | 圓弧 | 矩形範圍 + 起始/掃描角度 |
| DrawBezier | 三次貝茲曲線 | 4 控制點 |
| DrawBeziers | 連續貝茲曲線 | 點陣列 (3n+1 點) |
| DrawClosedCurve | 封閉樣條曲線 | 張力參數控制緊度 |
| DrawCurve | 開放樣條曲線 | 同上 |
| DrawEllipse | 橢圓輪廓 | 矩形範圍 |
| DrawPath | 路徑輪廓 | GraphicsPath 物件 |
| DrawPie | 扇形輪廓 | 矩形 + 起始/掃描角度 |
| DrawPolygon | 多邊形輪廓 | 點陣列 |
| DrawRectangle | 矩形輪廓 | 矩形/座標 |
| FillEllipse | 填充橢圓 | 畫刷 |
| FillPath | 填充路徑 | 畫刷 |
| FillPie | 填充扇形 | 畫刷 |
| FillPolygon | 填充多邊形 | 畫刷 |
| FillRectangle | 填充矩形 | 畫刷 |
| FillRectangles | 批量填充矩形 | 同一畫刷 |
| FillRegion | 填充區域 | Region 物件 |
進階範例:路徑構造複雜區域並漸層填充
GraphicsPath path;
Point pts[8] = {
Point(50,200), Point(100,150), Point(160,180), Point(200,200),
Point(230,150), Point(220,50), Point(190,70), Point(130,220)
};
path.AddClosedCurve(pts, 8, 0.5f); // 張力 0.5
PathGradientBrush pthGrBrush(&path);
pthGrBrush.SetCenterColor(Color(255, 0, 0, 255));
Color colors[] = { Color(0, 0, 0, 255) };
INT count = 1;
pthGrBrush.SetSurroundColors(colors, &count);
Pen pen(Color::Blue, 3);
graphics.DrawClosedCurve(&pen, pts, 8, 0.5f);
graphics.FillPath(&pthGrBrush, &path);
六、MFC 整合 GDI+ 最佳實踐
- 初始化/關閉:
GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 在 CWinApp::InitInstance 執行;GdiplusShutdown(gdiplusToken); 在 ExitInstance 執行。
- OnPaint 中使用:
void CMyView::OnPaint() {
CPaintDC dc(this);
Graphics graphics(dc.m_hDC);
// 設定高品質
graphics.SetSmoothingMode(SmoothingModeAntiAlias);
graphics.SetTextRenderingHint(TextRenderingHintClearTypeGridFit);
graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
// 繪圖代碼...
}
- 雙緩衝防閃爍:GDI+ 內建雙緩衝,或手動
Bitmap bmp(width, height); Graphics g(&bmp); ... dc.DrawImage(&bmp, 0, 0);。
- 座標系注意:GDI+ 使用 **單精度浮點數** 座標,MFC
CRect/CPoint 為整數,**不可直接混用**,需顯式轉換。
總結
GDI+ 以 **Graphics** 為核心畫布,**Pen/Brush** 為風格定義,**Matrix** 為幾何變換,**Path/Region** 為複雜形狀構建,構成完整現代繪圖體系。掌握座標空間轉換、漸層畫刷構造、矩陣變換數學本質,即可實現從商務圖表、CAD 繪圖到遊戲 UI 的高品質視覺效果。
- 上一篇文章: No
- 下一篇文章: Visual C++.NET 程式設計講座之八:程式安裝與部署 — 建立 MSI 安裝包、自定義介面、序號驗證、開始選單/桌面捷徑
Copyright ©
程式碼之家 All Rights Reserved