Windows 繪圖不直接操作硬體像素,而是透過 設備內容(Device Context,DC) 這個邏輯繪圖平面。DC 是一個資料結構,封裝了 GDI 所需的所有繪圖狀態:關聯的實體裝置、筆刷、字型、對映模式、裁剪區域等。程式必須先取得 HDC,繪圖後再歸還,否則會造成資源洩漏。
// 取得整個螢幕 DC
HDC hDC = ::GetDC(NULL);
::MoveToEx(hDC, 0, 0, NULL);
::LineTo(hDC, 200, 20);
::ReleaseDC(NULL, hDC); // 參數必須與 GetDC 配對
// 取得特定視窗客戶區 DC
HDC hDC = ::GetDC(m_hWnd);
::MoveToEx(hDC, 0, 0, NULL);
::LineTo(hDC, 200, 50);
::ReleaseDC(m_hWnd, hDC);
關鍵點:GetDC(NULL) 取得螢幕 DC,座標原點在螢幕左上角;GetDC(hWnd) 取得視窗客戶區 DC,原點在客戶區左上角。務必配對呼叫 ReleaseDC,否則 GDI 物件計數器會遞增導致系統資源耗盡。
CDC* pDC = GetDC();
pDC->MoveTo(0, 0);
pDC->LineTo(200, 100);
ReleaseDC(pDC);
MFC 將 HDC 包裝為 CDC*,提供物件導向介面,自動處理座標轉換與狀態管理,程式碼更簡潔。
MFC 提供三個 CDC 衍生類,建構子自動取得 DC,解構子自動釋放,彈性對應不同繪圖範圍:
| 類別 | 對應範圍 | 典型用途 | 建構/解構對應 API |
|---|---|---|---|
CClientDC | 視窗客戶區 | 一般繪圖、回應 WM_PAINT 外的即時繪製 | GetDC/ReleaseDC |
CWindowDC | 整個視窗(含非客戶區) | 繪製標題列、邊框、捲軸等非客戶區元素 | GetWindowDC/ReleaseDC |
CPaintDC | 視窗客戶區 | 僅限 OnPaint 內回應 WM_PAINT | BeginPaint/EndPaint |
void CDCDemoDlg::OnCclientdc() {
CClientDC dc(this); // 自動 GetDC
CBrush brush(RGB(255,0,0)); // 紅色筆刷
dc.FillRect(CRect(0,0,100,100), &brush); // 填滿矩形
} // dc 解構自動 ReleaseDC
void CDCDemoDlg::OnCwindowdc() {
CWindowDC dc(this); // 自動 GetWindowDC
CPen pen(PS_SOLID, 3, RGB(0,255,0)); // 3 像素實線綠筆
CPen* pOldPen = dc.SelectObject(&pen); // 選入並保存舊筆
dc.MoveTo(0, 0);
dc.LineTo(200, 200);
dc.SelectObject(pOldPen); // 恢復舊筆
} // dc 解構自動 ReleaseDC
void CDCDemoDlg::OnPointer() {
CWindowDC* pDC = new CWindowDC(this); // 堆疊配置
pDC->MoveTo(0, 0);
pDC->LineTo(200, 250);
delete pDC; // 手動刪除觸發解構子釋放 DC
}
注意:動態配置時必須成對 new/delete,否則 DC 不會被釋放。
CClientDC/CWindowDC/CPaintDC:RAII 機制確保不洩漏,程式碼最簡潔。CWnd::GetDC/ReleaseDC。掌握 DC 的取得與釋放機制,是 Windows 繪圖程式穩定、高效的基石。