1. 程式人生 > >VC中GDI繪圖上手必須瞭解清楚的幾個概念

VC中GDI繪圖上手必須瞭解清楚的幾個概念

如果我們使用過GDI+繪圖,那麼理解GDI繪圖就很容易,不論在GDI還是GDI+中繪圖,都需要一個繪圖的“畫板”,如果沒有這個“畫板”那麼我們所繪製的圖就沒有地方承載,自然也就不能顯示出來給人看見。
GDI+的繪圖畫板物件是一個Graphics物件,看起來,這個非常好理解,那是因為微軟在開發.net這個時已經更多考慮它的易用性,自然也就將名稱設定得要更易於理解。
GDI是MFC的繪圖系統,GDI中的繪圖“畫板”是什麼呢?
是DC(Device Context),意思是裝置上下文,也有人稱之為裝置環境。不管怎麼稱呼,我們必須記住一點,沒有DC(包括其子類)例項,我們的繪圖則沒有了“畫板”,所以在我們繪圖之前一定要建立或獲得一個DC例項。

裝置上下文(DC)
MFC中提供了幾種典型的DC類,如CDC、CPaintDC、CClientDC、CWindowsDC及CMetaFileDC。
這裡要特別注意到一個細節,這個細節對後面瞭解selectobject方法很有幫助,即DC在初始化的時候,系統會為其成員變數賦予預設的樣式。

我們可以通過dc的相關方法獲取當前的繪圖工具的GDI成員變數樣式(當然這些成員變數被隱藏了,我們不能直接訪問),如:
在這裡插入圖片描述

其中,CDC類可以和其他的DC類進行資料交換,因為DC類的是其他DC的基類。所以我們可以在程式碼中看到,常常用來做相容DC的都是CDC而不能使用其他的DC類。下面我們對最常用的CPaintDC和CClientDC分別講解。

CPaintDC
CPiantDC類是OnPaint()函式使用的裝置上下文類,它代表一個視窗的繪製畫面,也就是說,這個時候整個視窗就是“畫板”了。在基於對話方塊和檢視的例項中都可以接收WM_PAINT的訊息,凡是接受這個訊息的物件也就有這個OnPaint方法。在類嚮導的訊息與處理函式列表框中,我們可以都看到這樣的類表:
在這裡插入圖片描述
當我們選擇了WM_PAINT訊息,那麼MFC會自動為我們生成OnPaint的重寫,如下:
在這裡插入圖片描述
可以看出來,一個CPaintDC的例項化和CDC的例項化一樣,直接傳入當前類的指標即可。
當用戶改變了應用程式視窗的大小或者恢復了窗體先前被覆蓋的部分,應用程式澤會受到Widnows訊息佇列中分派下來的WM_PAINT訊息,那麼窗體或者檢視就會呼叫OnPaint方法。
在檢視類(CView)中,OnPaint被呼叫的時候,OnPaint會呼叫OnDraw函式,因此程式設計的時候經常在OnDraw中輸出圖形。

CClientDC
CClientDC類是客戶區的裝置上下文,客戶區就是指不包括邊框、標題欄、選單欄、工具欄、狀態列等介面元素的內部繪圖區。當構造CClientDC類的物件時自動呼叫API函式GetDC()即可獲得一個CClientDC的控制代碼,釋放則用Release()方法。一般我們需要在滑鼠或鍵盤事件或者自定義的方法進行圖形繪製操作,那麼CClientDC就是最好的選擇,如:
在這裡插入圖片描述

這裡,我們就在拖拽事件中用到了CClientDC。
CWindowsDC類,從名稱上我們便可以猜到它代表整個應用程式視窗區域的裝置上下文,包括邊框、標題欄、選單欄、工具欄、狀態列等。這裡我們不詳細講了,因為我們用到他們的時候較少。
瞭解了CDC,我們就有了繪圖的畫板,那麼我們還要有繪圖的其他工具才行。接下來我們介紹繪圖的其他及個必要方法,通過他們我們可以獲得繪圖時必要使用的必要工具和必要方法(CreateCompatibleDC和SelectObject)。

CDC的SelectObject方法
裝置上下文初始化時,系統會自動賦予其預設的GDI繪圖工具的樣式,有預設的畫筆、筆刷、字型樣式,如果我們不通過selectObject將我們自己建立的GDI物件選中為當前繪圖樣式,那麼MFC將仍然使用系統初始化時賦予DC的預設樣式。
所以,我們可以知曉該方法的作用是將使用者自己建立的GDI物件例項選擇到DC中去。SelectObject有多種過載形式,可以選擇使用者已經定製好的畫筆、筆刷、字型、點陣圖等不同型別的GDI物件例項。如:
在這裡插入圖片描述
選擇操作成功則返回該型別的指標(返回的上一次使用同類型的GDI物件),否則返回NULL。
有的繪製方法可以不需要事先呼叫selectobject

如:
如果你只是FillRect(hDC,&rc,hBrush);可以不用selectobject.
FillRect(hDC,&rc,hBrush);函式中有hBrush引數的意思是:你可以不使用當前device context中的brush(省得你自己再selectobject一次了).
比如,你把紅刷子選進device context,你可以用綠刷子來FillRect.
DC的SelectStockObject方法
它與SelectObject不同的是,SelectObject所選擇的物件必須先建立後選擇,引數為一個GDI的指標,SelectStockObject不必要先建立GDI物件,而是可以直接使用系統預置的堆物件,也就是說它所接收的引數是一個系統定義的巨集,如下:
在這裡插入圖片描述
我們可以看到,它接收的引數是一個整形值。

繪圖工具(GDI物件)
通過繪圖工具我們可以例項化GDI物件,如畫筆、筆刷、字型等,但我們在使用繪圖工工具的時候必須注意以下的嚴格四個步驟:
建立GDI
選擇GDI(將物件選擇進入DC中)
使用GDI
(使用完後)釋放GDI
如以下程式碼示例:
在這裡插入圖片描述
CDC的CreateCompatibleDC方法
該函式建立一個與指定裝置相容的記憶體裝置上下文環境(DC),大家可能對這句話不太理解。我們可以回憶一下前面的內容,我們說CDC類是其他DC類的基類,而且只有它可以跟其他DC進行資料交換,也就是說只有它才可以和其他DC類進行相容。所以,也只有CDC才有這個方法,才能承擔建立一個與指定“DC”型別相相容的DC。
我們看一段這個方法的例項程式碼:

在這裡插入圖片描述
這段程式碼完成的工作就是將MemDC例項化成和dc相容的DC了。
也許,我們又要問了,為什麼要建立這個相容上下文呢?直接將圖形繪製到dc上不就完了嗎?
實際上,直接繪製在CPaintDC或者CClientDC上肯定是可以的。
下面我們來具體瞭解一下這個函式:
函式原型:HDC CreateCompatibleDC(HDC hdc);
引數hdc:
表示現有裝置上下文環境的控制代碼,如果該控制代碼為NULL,該函式建立一個與應用程式的當前顯示器相容的記憶體裝置上下文環境。
返回值:
如果成功,則返回記憶體裝置上下文環境的控制代碼;如果失敗,則返回值為NULL。

CreateCompatibleDc函式只適用於支援光柵操作的裝置,應用程式可以通過呼叫GetDeviceCaps函式來確定一個裝置是否支援這些操作。
當不再需要記憶體裝置上下文環境時,可呼叫DeleteDc函式刪除它。
以下是一段MSN上的程式碼示例,我們可以通過它來了解這個函式的使用:
在這裡插入圖片描述
有許多老的VC程式依舊在使用GDI繪圖,引入了.net框架支援的VC新版本也許可以考慮使用GDI+了,有關GDI+的繪圖請參考我的C#中GDI+繪圖輕鬆入門博文。