GDI 繪圖函式皆為有狀態操作,核心在於裝置內容。取得 HDC 三大途徑:
BeginPaint / EndPaint:回應 WM_PAINT 專用。GetWindowDC / ReleaseDC:整個視窗區域(含邊框、標題列)。GetDC / ReleaseDC:僅客戶區。MFC 封裝類別對應關係:
| MFC 類別 | 封裝對象 | 建構/解構行為 |
|---|---|---|
CPaintDC | BeginPaint/EndPaint | 建構呼叫 BeginPaint,解構呼叫 EndPaint |
CWindowDC | GetWindowDC/ReleaseDC | 建構呼叫 GetWindowDC,解構呼叫 ReleaseDC |
CClientDC | GetDC/ReleaseDC | 建構呼叫 GetDC,解構呼叫 ReleaseDC |
CDC 將需 HDC 參數的 GDI 函式封裝為成員函式,HDC 成為其成員變數。
繼承 CStatusBar,覆寫 OnEraseBkgnd 與 OnPaint:
OnEraseBkgnd:以灰色筆刷填滿背景。OnPaint:逐格繪製圓角矩形、填入文字、繪製右下角調整大小圖示(六個小圓)。關鍵技巧:SelectObject 切換筆、刷、字體,用畢必須還原原始物件,否則造成 GDI 物件洩漏。兩種還原策略:
SelectObject(pOld) 還原。GetStockObject(NULL_BRUSH),無需還原。特例:FillRect 直接接受筆刷參數,不依賴 DC 狀態。
閱讀、除錯他人原始碼是最快累積 GDI 經驗的途徑。
InitInstance 加入 GdiSetBatchLimit(1)(僅 _DEBUG),強制每個 GDI 呼叫即時生效,避免批次處理導致除錯時畫面不更新。原理:先在相容記憶體 DC 繪製完畢,再一次 BitBlt 複製到螢幕 DC。
HDC hMemDC = CreateCompatibleDC(hDestDC);
HBITMAP hBmp = CreateCompatibleBitmap(hDestDC, rc.right, rc.bottom);
HBITMAP hOldBmp = SelectObject(hMemDC, hBmp);
// ... 在 hMemDC 上繪圖 ...
BitBlt(hDestDC, rc.left, rc.top, rc.right, rc.bottom, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldBmp);
DeleteObject(hBmp);
DeleteDC(hMemDC);
封裝為 CMemDC 類別,利用建構/解構自動管理,除錯時可透過條件編譯切換是否使用記憶體 DC,兼顧效能與除錯便利性。