戏说 Windows GDI (1)
0.題記:
作為QT開發的支持者和踐行者,明知道MFC已經過時,但是還不得不用;老板要求,項目組師兄弟代碼兼容Balabala~也許這就是中國式項目研發。
好啦,聊點正經事......
1.設備描述表(Device Context,DC):通往各種輸出設備的橋梁
在單任務環境如MS-DOS中,運行中的應用程序隨時可自由的想做他想做的事,無論是在屏幕上畫一條線,重新編寫適配器的調色板,還是轉換到另一種圖像模式。而在窗口化多任務環境如Windows中,程序則無此自由。因為程序A的輸出必須與程序B的輸出相隔離。首先,這意味著各程序的輸出必須限制在自己的窗口中。GDI(Graphic Device Inteface,GDI)使用一簡單的機制保證在窗口中畫圖的各程序遵循這些規則。這種機制即為“設備描述表”,也就是我們常說的DC。
當Windows程序在屏幕、打印機或其他輸出設備上畫圖時,他并不是將像素直接輸出到設備上,而是將圖繪制到由設備描述表表示的邏輯意義上的“顯示平面”上去。設備描述表是深寓于Windows中的一種設備結構,它包含GDI需要的關于顯示平面情況的描述字段,包括相連的物理設備和各種各樣的狀態信息。在平面上畫圖之前,Windows程序從GDI獲取設備描述表的句柄,并且每次調出GDI輸出函數時,將句柄返回給GDI。若沒有有效的設備描述表聚丙,則GDI不會畫第一個像素。
再利用MFC編制Windows程序時,設備描述表具有更加突出的作用。除了可以作為通往各種輸出設備的橋梁之外,設備描述表對象還封裝了程序用來產生輸出的GDI函數。在MFC中,我們不再需要捕獲設備描述表句柄和調用GDI輸出函數,至少不用直接捕獲和調用,而是通過創建設備描述表對象并調用它的成員函數來畫圖。
2.MFC設備描述表類
在MFC應用程序中獲取設備描述表的一種方法是調用CWnd::GetDC(),它返回指向表示Windows設備描述表的CDC對象的指針。在畫圖完畢時,要用CWnd::ReleaseDC()釋放由GetDC()獲得到的設備吧、描述表的指針。具體如下面程序所示:
CDC* pdc = GetDC(); //do some drawing ReleaseDC(pdc);再這里需要我們注意的是,如果在OnPain處理程序中時,則需要Cwnd::BeginPaint和CWnd::EndPaint分別代替GetDC()和ReleaseDC(),以保證合理地處理WM_PAINT消息:
PAINTSTRUCT PS; CDC* pDC = BeginPaint( & ps ); //do some drawing EndPaint( & ps );為避免要記住獲取和釋放設備描述表時需要調用的函數(并且為了確保在使用設備描述表的消息處理程序結束時設備描述表能合理的被釋放)MFC提供了CDC派生類,具體如下:
| 類名 | 描述 |
| ?CPaintDC | ?用于在窗口客戶區畫圖(僅限于OnPaint處理程序) |
| ?CClientDC | ?用于在窗口客戶區畫圖(除了OnPaint以外的任何程序中) |
| ?CWindowDC | ?用于在窗口內任意地方畫圖,包括非客戶區 |
| ?CMetaFileDC | ?用于向GDI原文件畫圖 |
這些類在設計的時候可直接進行實例化(類是事物的抽象封裝,對象是類的具體化)各個類的構造函數和析構函數調用相應的函數捕獲和釋放設備描述表,從而使得設備描述表的使用非常方便:
CPaintDC dc(this);//該參數傳給CPaintDC的類構造函數,確定設備描述表所屬的窗口 //do some drawing當在棧上構造設備描述表對象時,若對象的生命周期結束,則它的析構函數會被自動調用。而且析構函數一旦被調用,設備描述表就會被返回給Windows。在堆上用new創建的設備描述表時,一定要注意親自釋放設備描述表。示例如下:
CPaintDC *pDC = new CPaintDC (this);//堆上創建指向CPaintDC的對象指針 delete pDC;CPaintDC類:
MFC的CPaintDC類響應WM_PAINT消息,允許在窗口客戶區畫圖。但是,需要注意。我們只能在OnPaint處理程序中使用,不能再其他別的地方應用。WM_PAINT消息有一點與其他Windows消息都不同。如果處理程序調用Windows的::BeginPaint()和::EndPaint函數失敗,那么不管有多少繪圖工作,都不能將該消息從消息隊列中刪除。因此,應用程序講一遍又一遍的處理同一個WM_PAINT消息,這不就陷入死循環了嗎?而通過分別從CPaintDC的構造函數和析構函數中調用::BeginPaint和::EndPaint,CPaintDC能保證陷入死循環這種事不發生!
CClientDC和CWindowDC類:
Windows程序不是總將繪圖限制在OnPaint上,如果編寫一個應用程序,只要以單擊鼠標嗎,應用程序就在屏幕上畫一個圓餅,那么我們就希望在接收到按鈕單擊消息時就立刻畫圓,而不必刻意的去等待WM_PAINT消息。這就是CClientDC存在的價值。CClientDC創建了可以在OnPaint外使用的用戶區域設備描述表。下面示例程序使用了CClientDC創建了兩個CDC成員函數,來完成了在鼠標左鍵被單擊時畫一個X鏈接串口客戶區四角的功能。
3.設備描述表屬性
下面總結一下設備描述表中最常用的屬性和訪問這些屬性所用的CDC函數:
| Attribute | Default | Set with | Get with |
| 文本顏色 | Black | CDC::SetTextColor | CDC::GetTextColor |
| 背景顏色 | White | CDC::SetBkColor | CDC::GetBkColor |
| 背景模式 | OPAQUE | CDC::SetBkMode | CDC::GetBkMode |
| 映射模式 | MM_TEXT | CDC::SetMapMode | CDC::GetMapMode |
| 繪圖模式 | R2_COPYPEN | CDC::SetROP2 | CDC::GetROP2 |
| 當前位置 | (0,0) | CDC::MoveTo | CDC::GetCurrentPosition |
| 當前畫筆 | BLACK_PEN | CDC::SelectObject | CDC::SelectObject |
| 當前畫刷 | WHITE | CDC::SelectObject | CDC::SelectObject |
| 當前字體 | SYSTEM_FONT | CDC::SelectObject | CDC::SelectObject |
毫無疑問,對于Windows編程的新手來說,GDI編程中最困難的部分就是映射模式(mapping mode)。映射模式用于確定從邏輯坐標值到設備坐標值的轉換方式。傳送給CDC輸出函數的是邏輯坐標值。設備坐標值是指窗口相應的像素點位置。調用dc.Rectangle(0,0,200,200)函數是,不知告訴GDI畫一個200個像素點寬、100個像素點高的矩形,而是告訴它畫一個200個單位寬、100個單位高的矩形。在默認映射模式MM_TEXT下,一個像素點錢錢相當于一個單位。
總結
以上是生活随笔為你收集整理的戏说 Windows GDI (1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博客屏蔽搜索引擎只是个笑话!!
- 下一篇: 在我还是14岁的时候那会学C++