MFC中的DC,CDC和HDC

                                                         MFC中的DC,CDC和HDC

       設備描述表(DC是Windows中的一種數據結構,它包含GDI需要的所有關於顯示界面情況的描述字段,包括相連的物理設備和各種各樣的狀態信息。

        圖形顯示功能是由顯卡來完成的,你想要利用顯卡的圖形顯示功能來完成你的圖形輸出,怎麼辦,給你一塊硬件能用嗎?好,現在廠商給你提供一個驅動程序,給你一些調用的接口,你就可以訪問了吧。但這種訪問是在驅動層,很麻煩,更麻煩的是,每個廠商給自己顯卡提供的驅動程序還不一樣,那我們寫的圖形輸出程序豈不是換臺機器(不一樣的顯卡)就得修改,一個字:累,兩個字:麻煩。現在一個救世主出現了,Bill兄,他讓他的兄弟們在驅動之上實現一個抽象層,當然也可以認爲是一箇中間層的軟件代碼(我們管他叫設備上下文如何,也叫設備描述表DC),由這些代碼和驅動打交道(當然,這些驅動得支持Windows平臺)。然後,他將這種實現封裝到動態鏈接庫中提供給我們使用,我們能通過動態鏈接庫暴露的API函數(相關概念見VC下半部分),得到一個這種實現(可以說是一種資源)的句柄,設備上下文的句柄(HDC),利用的這個句柄,就好像有了訪問這中實現的鑰匙了,以後就可以.......,剩下的參照VC上半部分的內容。

       設備描述表DC是一個定義一組圖形對象及其屬性、影響輸出的數據結構。windows提供設備描述表,用於應用程序和物理設備之間進行交互,從而提供了應用程序設計的平臺無關性。設備描述表又稱爲設備上下文,或者設備環境。 
  設備描述表是一種數據結構,它包括了一個設備(如顯示器和打印機)的繪製屬性相關的信息。所有的繪製操作通過設備描述表進行。設備描述表與大多WIN32結構不同,應用程序不能直接訪問設備描述表,只能由各種相關API函數通過設備描述表的句柄(HDC)間接訪問該結構。 
  設備描述表總是與某種系統硬件設備相關。比如屏幕設備描述表與顯示設備相關,打印機設備描述表與打印設備相關等等。 
  屏幕設備描述表,一般我們簡單地稱其爲設備描述表。它與顯示設備具有一定的對應關係,在windows GDI界面下,它總是相關於某個窗口或這窗口上的某個顯示區域。通常意義上窗口的設備描述表,一般指的是窗口的客戶區,不包括標題欄、菜單欄所佔有的區域,而對於整個窗口來說,其設備描述表嚴格意義上來講應該稱爲窗口設備描述表,它包含窗口的全部顯示區域。二者的操作方法完全一致,所不同的僅僅是可操作的範圍不同而已。 

windows 窗口一旦創建,它就自動地產生了與之相對應的設備描述表數據結構,用戶可運用該結構,實現對窗口顯示區域的GDI操作,如劃線、寫文本、繪製位圖、填充等,並且所有這些操作均要通過設備描述表句柄了進行。 

要說設備描述表就必須先說GDI(圖形設備接口)。我們要在程序窗口上顯示圖形或文本等,就可以使用這些GDI函數在程序上“畫畫”、“寫字”。設備描述表(DC)實際上是GDI內部保存的數據結構。設備描述表中的有些值是圖形化的“屬性”,這些屬性定義了一些GDI函數工作的情況,如:文本顏色、圖形填充的情況等。HDC是設備描述表句柄類型,句柄可以簡單的理解爲指針,被定義爲32位的無符號整數。  

             以上內容轉自:http://longzxr.blog.sohu.com/187934817.html

         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),以及色彩,調色板。除此之外還提供成員函數獲取和設置繪圖屬性,映射,控制視口,窗體範圍,轉換座標,區域操作,裁減,劃線以及繪製簡單圖形(橢圓,多邊形等)。成員函數也提供繪製文本,設置字體,打印機換碼,滾動,處理元文件。

其派生類:

         1.CPaintDC:封裝BeginPaint和EndPaint兩個API的調用。
(1)用於響應窗口重繪消息(WM_PAINT)的繪圖輸出。
(2)CPaintDC在構造函數中調用BeginPaint()取得設備上下文,在析構函數中調用EndPaint()釋放設備上下文。 EndPaint()除了釋放設備上下文外,還負責從消息隊列中清除WM_PAINT消息。因此,在處理窗口重畫時,必須使用CPaintDC,否則 WM_PAINT消息無法從消息隊列中清除,將引起不斷的窗口重畫。
(3)CPaintDC也只能用在WM_PAINT消息處理之中。
         2.CClientDC(客戶區設備上下文): 處理顯示器描述表的相關的窗體客戶區域。

     構造時自動調用GetDC函數,析構時自動調用ReleaseDC函數.一般應用於客戶區窗口的繪製。

     當需要處理一個鼠標的單擊,然後馬上畫出一個圓,你不能等到下一個WM_PAINT的消息到來才畫圖,而是馬上,這是就需要CclientDC了。它可以在OnPaint的外面創建一個客戶區域DC

    void CMainWindow::OnLButtonDown (UINT nFlags, CPoint point)
    {
        CRect rect;
        GetClientRect (&rect);

        CClientDC dc (this);
        dc.MoveTo (rect.left, rect.top);
        dc.LineTo (rect.right, rect.bottom);
        dc.MoveTo (rect.right, rect.top);
        dc.LineTo (rect.left, rect.bottom);
    }


         3.CWindowDC: 處理顯示器描述表相關的整個窗體區域,包括了框架和控 件(子窗體)。
(1)可在非客戶區繪製圖形,而CClientDC,CPaintDC只能在客戶區繪製圖形。
(2)座標原點是在屏幕的左上角,CClientDC,CPaintDC下座標原點是在客戶區的左上角。
(3)關聯一特定窗口,允許開發者在目標窗口的任何一部分進行繪圖,包含邊界與標題,這種DC同WM_NCPAINT消息一起發送。

      4.CMetaFileDC:與元文件相關的設備描述表關聯。

 

下面說下一些細點的知識點
1、CClientDC,CWindowDC
區別不大, 可以說 CWindowDC包含了CClientDC。 就拿記事本來說,CClientDC 就只是我們可以編輯文字的那個區域,是客戶區,CWindowDC 除了上面說的區域, 還包括菜單欄和工具欄等。

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

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

4、關於 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是否爲空等。
5、HDC和CDC相互轉換:

(1)、HDC到CDC的轉換:
方法一: 此方法在設備結束時不會銷燬原來的資源(即:hDC,hBitmap)
CDC *pDC = CDC::FromHandle(hDC);

方法二:此方法在設備結束時會銷燬原來的資源(即:hDC,hBitmap)
CDC dc;
dc.Attach(hDC);

(2)、CDC到HDC的轉換:

   CDC  dc;

   HDC  hDC;

   hDC = dc.GetSafeHdc();

6、首先:CDC 不可以釋放。 FromHandle 是通過 HDC 來創建了一個CDC 對象,以方便操作,釋放 DC 的操作應該針對於HDC 而非此CDC , 如果釋放了它   pDC->ReleaseDC,就會造成隱患。 
      HDC   hDC   =   GetDC(hWnd); 
      CDC   *pDC   =   CDC::FromHandle(hDC);  
      這兩者是指向的一個DC對象,只能釋放一次,而這個釋放應該針對 hDC 而非 pDC。

      然後:GetDC和ReleaseDC的調用匹配,CreateDC和DeleteDC的調用匹配。GetDC是從窗口獲取現有的DC,而CreateDC是創建DC,所以ReleaseDC和DeleteDC的作用一個是釋放,一個是銷燬。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章