圖形設備接口(Graphics Device Interface,GDI),把應用程序的函數調用傳遞給圖形設備驅動程序,由設備驅動程序來執行與硬件相關的函數。GDI嚮應用程序提供了一個設備無關的編程,同時以設備相關的格式和具體的硬件設備交互。
在MFC中使用GDI進行繪圖操作一般會涉及兩個對象,一是設備上下文對象,包括CDC及其派生類;二是GDI對象,包括CFont、CBrush、CPen等。
設備上下文
設備上下文(Device Context,DC),是一種Windows數據結構,包括與設備繪製屬性相關的信息。利用設備上下文可以實現向屏幕、打印機的輸出。
在應用程序中,通常在繪圖之前調用BeginPaint函數,然後在設備上下文中進行一系列繪圖操作,最後調用EndPaint函數結束繪製過程。
MFC中的設備上下文包括:CDC、CClientDC、CPaintDC、CWindowsDC等。他們之間的關係如圖4-1-1所示:
圖4-1-1 MFC中常見的設備上下文之間的關係
MFC把不同的上下文對象用不同的類進行了封裝,如下所示:
1) CDC:所有設備上下文類的基類。封裝了所有圖形輸出函數,包括矢量、光柵和文本輸出。
2) CClientDC:用於客戶區域的圖形輸出,需要直接在客戶區域進行繪製時使用。一般在響應非窗口重繪消息(如鍵盤輸入時繪製文本、鼠標繪圖)時使用,在其構造函數中自動調用GetDC,在其析構函數中自動調用ReleaseDC函數。CClientDC對象聯繫的DC是窗口的客戶區。
3) CPaintDC:用於響應窗口重繪消息消息(WM_PAINT)時的繪製輸出。CPaintDC繼承自CDC,在其構造函數中自動調用BeginPaint函數。在其析構函數中自動調用EndPaint函數。EndPaint除了釋放設備上下文外,還負責從消息隊列中清除WM_PAINT消息。因而在處理窗口重繪時,必須使用CPaintDC,否則WM_PAINT消息無法從消息隊列中清除,將引起不斷的窗口重繪。CPaintDC也只能用在WM_PAINT消息處理中。
4) CWindowsDC:用於窗口客戶區和非客戶區(包括窗口邊框、標題欄、控制按鈕等)的繪製。
獲取整個屏幕區域,包括客戶區和非客戶區。一句話概括:
CDC | 任何dc | 相當於CreateDC、DeleteDC |
CClientDC | 客戶區dc | 相當於GetDC、ReleaseDC |
CPaintDC | 無效區dc | 相當於BeginPaint、EndPaint |
CWindowDC | 整窗口dc | 相當於GetWindowDC、 ReleaseDC |
設備上下文相關函數整理如下:
- GetSafeHdc: 返回輸出設備上下文m_hDC。
- SaveDC:保存設備上下文當前狀態。
- RestoreDC: 恢復SaveDC保存的設備上下文以前狀態。
- ResetDC:更新m_hAttribDC設備上下文。
- GetDeviceCaps: 獲取有關給定顯示設備功能的指定類型指定設備信息。
- IsPrinting:確定正在使用的設備上下文是否用於打印。
GDI對象
繪圖不僅需要場景,也需要工具。可以把設備上下文理解爲GDI繪圖的場景,那麼GDI對象就是工具。MFC主要提供了以下幾種GDI對象:
CPen:用來繪製線條;
CBursh:用來填充繪製對象的內部;
CBitmap:用來操作位圖對象;
CFont:用來繪製文本;
CPalette:用於應用程序和彩色輸出設備(如顯示器)之間的接口。
GDI繪圖
使用GDI進行圖形繪製的一般流程如下所示:
- 創建GDI對象;
- 創建或取得設備上下文對象;
- 使用SelectObject把GDI對象選入設備上下文;
- 使用圖形輸出函數在指定上下文中繪製圖形。
GDI繪圖過程經常會遇到出現抖動的問題,主要原因是對屏幕設備DC操作太過頻繁,解決辦法是首先把所有繪圖操作都在內存DC中操作,然後這些內存DC統一繪製到一個總的內存DC中,然後再把這個總的內存DC一次性繪製到屏幕DC,這樣就不會出現抖動。這就是通常所說的“雙緩存技術”,將在第4.4節中以實例的形式介紹。