MFC 画图
個人感覺這一篇總結的不錯:
精華:
Windows中負責圖形輸出的是GDI(即GraphicDeviceInterface,圖形設備接口)。這是Windows與硬件無關的圖形輸出模式的體現。GDI建立在硬件抽象層(HAL)之上,屏蔽了不同輸出設備之間的差異,從而為用戶提供了一個統一的“標準輸出設備”。但是,與DOS不同,Windows是多任務、進程獨立的,每一個窗口都應該有一個獨立的輸出通道。這樣,GDI又使用了一種簡單的機制來保證在窗口中畫圖的不同程序之間能共享“設備”而又互不干擾。這個機制就是DC(DeviceContext,設備描述表)。
有人把DC比喻成畫家的畫室,這里有畫布、畫刷、畫筆等等很多工具。
就畫布而言,畫布形式可以不同,是的,我可以在桌上(desktop)的紙上(window)畫,也可以就畫在桌面上,還可以畫在墻上(管的著嗎!^_^)。
為此,WindowsMFC提供了四種不同的DC環境(封裝為C 類),以標明不同的繪制權限,即:
CPaintDC,用于在窗口客戶區畫圖(僅限于在OnPaint處理函數中使用);
CClientDC,也用于在窗口客戶區畫圖(限于在OnPaint處理函數之外使用);
CWindowDC,用于在窗口內任意地方畫圖,包括非客戶區;
CMetaFileDC,用于繪制GDI圖元文件。 www.mscto.com
這些類都可以直接實例化,如:
CPaintDCdc(this);//this表示此DC所屬窗口為當前窗口
創建了一個CPaintDC對象dc。
CWindowDC一般不常用,如果想在窗口非客戶區畫圖,可借助OnNcPaint()處理函數捕獲WM_NCPAINT消息。
剛才說了,DC中還有畫刷、畫筆等。這些都是DC的屬性,可通過DC自身(調用其成員函數)獲得。
DC屬性包括文本顏色、背景顏色、映射模式、繪圖模式、當前位置、當前畫筆(刷)和當前字體等。
畫筆(Pen)、畫刷(Brush)都是獨立的GDI對象,可通過CDC成員函數SelectObject()選入DC。同樣操作方式的對象還有字體(Font)、位圖(Bitmap)、調色板(Palette)和區域(Region)。
關于SelectObject():在創建好GDI對象之后,SelectObject()接收該對象指針,其返回值為先前選入DC的相同類型的對象指針(通常用來恢復DC用)。
Windows也預先定義了一些畫筆、畫刷、字體以及其他一些GDI對象。這些對象稱為備用對象,用CGdiObject::SelectStockObject()選入。CGdiObject是表示GDI對象的CPen、CFont等類的基類。備用對象的屬性說明可以查MSDN。
由CGdiObject派生類創建的畫筆、畫刷和其他對象都要占用內存資源,因此使用后一定要刪除它們。處理方法與其他window對象類似。在棧中創建的對象,當此CGdiObject超出范圍時會自動析構。在堆中用new創建的CGdiObject對象,可通過調用CGdiObject::DeleteObject顯式刪除(這會引起對GDI對象析構函數的調用)或用相應的delete運算符。如果是備用對象,則沒必要專門刪除,留給windows就可以了。
VC 有一種簡單的方法用來確定是否成功的刪除了GDI對象:只要在調試狀態下運行應用程序的調試版本即可。在應用程序結束時,沒有釋放的資源會顯示在調試窗口中。
一些知識點:
1.繪圖模式:GDI將象素點輸出到邏輯顯示平面上時,并不只是簡單的輸出象素顏色,而是通過一系列布爾運算將輸出象素點的顏色和輸出目標位置上象素點的顏色進行合成再顯示。所使用的邏輯運算關系就由DC的繪圖模式確定。使用CDC:SetROP2()可更改繪圖模式(ROP2,RasterOperationTo)。默認繪圖模式是R2_COPYPEN,直接將象素點輸出到顯示平面上。常用的還有R2_NOT,用于實現鼠標繪圖時的Rubber技術。
2.映射模式:這是DC的屬性之一,用于確定從邏輯坐標到設備坐標的轉換(或者說mapping,映射)方式。設備坐標是指窗口中相應的象素點位置。單位只有象素一種。而邏輯坐標依映射模式不同而單位各異。如默認的MM_TEXT模式下,一個單位恰恰是一個象素點。MM_LOENGLISH模式下,一個單位則相當于百分之一英寸長。windows支持8種映射模式,其中的MM_ISOTROPIC和MM_ANISOTROPIC是可編程的。這意味著是用戶而不是windows確定從邏輯坐標到設備坐標的轉換方式。換句話說,就是用戶來自行定制邏輯單位的實際大小。這兩種模式最常用于根據窗口尺寸按比例自動調節畫圖輸出大小的場合。兩者之間的唯一區別在于:前者中X方向和Y方向具有同一縮放比例因子。設置映射模式的函數是CDC::SetMapMode()。
3.坐標系常用技術:
1)坐標變換:調用CDC::LPtoDP可將邏輯坐標值轉換為設備坐標值。反之,調用CDC::DPtoLP可將設備坐標值轉換為邏輯坐標值。在相應鼠標單擊區域命中測試時,將使用這兩個函數。因為鼠標單擊得到的是設備坐標,而很多GDI函數使用邏輯坐標,必須轉換為統一坐標,操作才有意義。
2)原點移動:默認方式下,DC的原點位于相應顯示平面的左上角。MFC提供了兩個CDC類成員函數,可改變原點位置。CDC::SetWindowOrg()移動窗口原點,CDC::SetViewportOrg()移動視圖原點(詳見MSDN)。一般只能使用兩者之一。原點移動技術在邊框滾動條設置時有所體現。
3)用戶坐標與屏幕坐標:前者是設立在窗口客戶區左上角的設備坐標值,后者是原點位于屏幕左上角的設備坐標值。兩者的相互轉換用函數是CWnd::ClientToScreen()和CWnd::ScreenToClient()。
4.GDI繪圖函數
1)畫線:包括MoveTo、LineTo、Polyline、PolylineTo、Arc、ArcTo、PolyBezier等。其中Polyline和PolylineTo都可以一次畫多條線,兩者的區別是PolylineTo使用DC的當前位置,而Polyline則不需要。ArcTo在win98下未實現。另外,所有GDI畫線函數有一個共同特點,就是從不畫最后一個象素點。
2)畫圖形:畫封閉圖形的GDI函數以外接矩形的坐標為參數。常用函數有Rectangle、Ellipse、RoundRect、Pie、Chord等。
5.畫筆與畫刷:在MFC中,畫筆對象封裝為CPen類,畫刷對象封裝為CBrush類。創建兩者都有三種方法。最簡單的就是構造一個CPen對象,直接給出所用參數進行初始化。第二種方法是調用一個未初始化的CPen對象,用CreatePen()初始化。還有一種方法是構造一個未初始化的CPen對象,通過向LOGPEN結構中填充描述畫筆特性的參數,然后調用CPen::CreatePenIndirect()生成畫筆。畫刷基本相同。
1)CPen:windows用當前選入DC的畫筆繪制線條,并給封閉圖形鑲制邊框。畫筆有三個特性,即樣式、寬度和顏色。樣式有PS_SOLID、PS_INSIDEFRAME、PS_NULL等。PS_NULL一般稱其為“NULL畫筆”,想畫一個沒有邊框的圖形,就用到它了。筆寬以邏輯單位給出,實際意義與當前映射模式相同。顏色是通過RGB宏把三個獨立顏色成分的值合成為一個可傳遞給GDI的COLORREF值來確定的。
2)CBrush:畫刷有三種基本類型,即單色、帶陰影線和帶圖案。其中圖案畫刷允許用位圖填充圖形內部(這樣,窗口背景也就沒啥新鮮的了)。常用函數有
CDC::SetBkMode()、CDC::SetBkColor()等。
6.文本與字體:CDC有一打文本處理函數,重要的幾個是DrawText、TextOut、GetTextMetrics、SetTextColor和SetTextAlign等。其中GetTextMetrics()傳給TEXTMETRIC結構關于字體性質的相關信息。字體是一組具有特定尺寸(高度)和字樣的字符;字樣指示字體共有屬性,如粗細等。字體封裝在CFont類中,建立字體對象,要在CFont構造之后,再調用CFont的成員函數CreateFont或CreateFontIndirect等來建立GDI字體資源。針對字體,有一個LOGFONT結構,其中定義了字體的所有特性。也可通過填充它來創建字體。
后記:寫這一章的筆記時有一種被作者牽著鼻子走的感覺。知識點太多,寫出來有一種羅列或拼湊的嫌疑。我不希望這樣,但想一想,技術也就是這樣。所以我希望大家看的時候,能夠思考著看,而不是記憶著看。思考著看只要求我們知道技術點、怎么用,用熟了,用多了,也就記住了。精華是濃縮的,至于如何把它化開,可要靠你自己了。
?
轉載于:https://www.cnblogs.com/van9ogh/archive/2011/09/22/2446372.html
總結
- 上一篇: Kafka 为什么能那么快的 6 个原因
- 下一篇: 已经是最大股东却还要全资收购!腾讯看上了