1. 程式人生 > >介面程式設計總結(1)

介面程式設計總結(1)

DC(裝置描述表)
解:Windows應用程式通過為指定裝置(螢幕,印表機等)建立一個裝置描述表(Device Context, DC)在DC表示的邏輯意義的“畫布”上進行圖形的繪製。DC是一種包含裝置資訊的資料結構,它包含了物理裝置所需的各種狀態資訊。Win32程式在繪製圖形之前需要獲取DC的控制代碼HDC,並在不繼續使用時釋放掉。
在c++ 程式設計中常會見到HDC,CDC,CClientDC,CPaintDC,CWindowDC這樣的類
HDC是DC的控制代碼,API中的一個類似指標的資料型別.
CDC是MFC的DC的一個類
CDC等裝置上下分類,都含有一個類的成員變數:m_nHdc;即HDC型別的控制代碼.
CDC及其派生類的繼承檢視:
CObject
public |------CDC
public |------|------CClientDC
public |------|------CPaintDC
public |------|------CWindowDC
public |------|------CMetaFileDC
(注意: 除CMetaFileDC以外的三個派生類用於圖形繪製.)
CDC類定義了一個裝置描述表相關的類,其物件提供成員函式操作裝置描述表進行工作,如顯示器,印表機,以及顯示器描述表相關的視窗客戶區域。
通過CDC的成員函式可進行一切繪圖操作。CDC提供成員函式進行裝置描述表的基本操作,使用繪圖工具,選擇型別安全的圖形裝置結構(GDI),以及色彩,調色盤。除此之外還提供成員函式獲取和設定繪圖屬性,對映,控制視口,窗體範圍,轉換座標,區域操作,裁減,劃線以及繪製簡單圖形(橢圓,多邊形等)。成員函式也提供繪製文字,設定字型,印表機換碼,滾動,處理元檔案。
其派生類:
CPaintDC: 封裝BeginPaint和EndPaint兩個API的呼叫。
(1)用於響應視窗重繪訊息(WM_PAINT)是的繪圖輸出。
(2)CPaintDC 在建構函式中呼叫BeginPaint()取得裝置上下文,在解構函式中呼叫EndPaint()釋放裝置上下文。EndPaint()除了釋放裝置上下文外,還負責從訊息佇列中清除WM_PAINT訊息。因此,在處理視窗重畫時,必須使用CPaintDC,否則WM_PAINT訊息無法從訊息佇列中清除,將引起不斷的視窗重畫。
(3)CPaintDC也只能用在WM_PAINT訊息處理之中。
CClientDC(客戶區裝置上下文): 處理顯示器描述表的相關的窗體客戶區域。用於客戶區的輸出,與特定視窗關聯,可以讓開發者訪問目標視窗中客戶區,其建構函式中包含了GetDC,解構函式中包含了ReleaseDC。
CWindowDC: 處理顯示器描述表相關的整個窗體區域,包括了框架和控制元件(子窗體)。
(1)可在非客戶區繪製圖形,而CClientDC,CPaintDC只能在客戶區繪製圖形。
(2)座標原點是在螢幕的左上角,CClientDC,CPaintDC下座標原點是在客戶區的左上角。
(3)關聯一特定視窗,允許開發者在目標視窗的任何一部分進行繪圖,包含邊界與標題,這種DC同WM_NCPAINT訊息一起傳送。
CMetaFileDC: 與元檔案相關的裝置描述表關聯。

CDC提供兩個函式,GetLayout和SetLayout用於反轉裝置描述表的佈局。用於方便阿拉伯,希伯來的書寫文化習慣的設計,以及非歐洲表中的字型佈局。
CDC 包含兩個裝置描述表,m_hDC和m_hAttribDC對應於相同的裝置,CDC為m_hDC指定所有的輸出GDI呼叫,大多數的GDI屬性呼叫由 m_hAttribDC控制。(如,GetTextColor是屬性呼叫,而SetTextColor是一種輸出呼叫。)
下面用一些簡單的程式碼看看如果使用這些類
HDC使用, 每次畫線等操作都不MFC封裝的類多了個HDC的引數
執行在哪個裝置描述表操作
HDC hdc=::GetDC(m_hWnd);//m_hWnd == this->m_hWnd 即當前視窗控制代碼
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);//必須和GetDC配對
可以看到HDC的使用較麻煩, 而且如果::GetDC和::ReleaseDC不配對的話,會造成錯誤
CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);

CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

CWindowDC dc(this);
CWindowDC dc2(GetDesktopWindow());//獲得整個桌面的控制代碼, 一些桌面特效程式使用
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

CPaintDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

可以看到 MFC 的類使用方便很多, 因為它們都在建構函式和解構函式呼叫了響應的函式進行DC的獲取和釋放.
下面說下一些細點的知識點
CClientDC,CWindowDC 區別不大, 可以說 CWindowDC包含了CClientDC 就拿記事本來說
CClientDC 就只是白白的我們可以編輯文字的那個區域是客戶區
CWindowDC 除了上面說的白白區域, 還包括選單欄和工具欄等

CClientDC和CWindowDC 與 CPaintDC 的區別大點
在DC的獲取方面 CClientDC和CWindowDC 使用的是並只能是 GetDC 和 ReleaseDC
CPaintDC 使用的是並只能是 BeginPaint 和 EndPaint

CPaintDC 只能用在響應 WM_PAINT 事件
CClientDC,CWindowDC 只能用在響應 非WM_PAINT 事件


關於 WM_PAINT 事件
系統會在多個不同的時機發送WM_PAINT訊息:當第一次建立一個視窗時,當改變視窗的大小時,當把視窗從另一個視窗背後移出時,當最大化或最小化視窗時,等等,這些動作都是由系統管理的,應用只是被動地接收該訊息,在訊息處理函式中進行繪製操作;大多數的時候應用也需要能夠主動引發視窗中的繪製操作,比如當視窗顯示的資料改變的時候,這一般是通過InvalidateRect和InvalidateRgn函式來完成的。InvalidateRect和 InvalidateRgn把指定的區域加到視窗的Update Region中,當應用的訊息佇列沒有其他訊息時,如果視窗的Update Region不為空時,系統就會自動產生WM_PAINT訊息。系統為什麼不在呼叫Invalidate時傳送 WM_PAINT訊息呢?又為什麼非要等應用訊息佇列為空時才傳送WM_PAINT訊息呢?這是因為系統把在視窗中的繪製操作當作一種低優先順序的操作,於是儘可能地推後做。不過這樣也有利於提高繪製的效率:兩個WM_PAINT訊息之間通過InvalidateRect和InvaliateRgn使之失效的區域就會被累加起來,然後在一個WM_PAINT訊息中一次得到更新,不僅能避免多次重複地更新同一區域,也優化了應用的更新操作。像這種通過 InvalidateRect和InvalidateRgn來使視窗區域無效,依賴於系統在合適的時機發送WM_PAINT訊息的機制實際上是一種非同步工作方式,也就是說,在無效化視窗區域和傳送WM_PAINT訊息之間是有延遲的;有時候這種延遲並不是我們希望的,這時我們當然可以在無效化視窗區域後利用SendMessage 傳送一條WM_PAINT訊息來強制立即重畫,但不如使用Windows GDI為我們提供的更方便和強大的函式:UpdateWindow和RedrawWindow。UpdateWindow會檢查視窗的Update Region,當其不為空時才傳送WM_PAINT訊息;RedrawWindow則給我們更多的控制:是否重畫非客戶區和背景,是否總是傳送 WM_PAINT訊息而不管Update Region是否為空等。