Windows編程 第六回 又見裝置描述表

來源:互聯網
上載者:User

-----路過的朋友,若發現錯誤或有好的建議,歡迎在下面留言,謝謝!-----

    裝置描述表還真是十分重要,以至於我們在這裡還要再學習它。這節內容比較少,相信你很快就應該能看完。Let’go!

擷取裝置描述表控制代碼

     複習:當你想在一個圖形輸出裝置(諸如螢幕或者印表機)上繪圖時,你首先必須獲得一個裝置描述表(或者DC)的控制代碼。將控制代碼傳回給程式時,Windows就給了你使用裝置的許可權。然後你在GDI函數中將這個控制代碼作為一個參數,向Windows標識你想在其上進行繪圖的裝置。如果在處理一個訊息時取得了裝置描述表控制代碼,應該在退出視窗函數之前釋放它(或者刪除它)。一旦釋放了控制代碼,它就不再有效了。

Windows提供了幾種取得裝置描述表控制代碼的方法,如下。

方法一:

      這是擷取並釋放裝置描述表控制代碼最常用的方法,即在處理WM_PAINT訊息時使用BeginPaint和EndPaint函數。這兩個函數需要程式的視窗控制代碼和PAINTSTRUCT結構的變數的地址為參數。Windows程式員通常把這一結構變數命名為ps並且在視窗過程中定義它:

PAINTSTRUCT ps ;

在處理WM_PAINT訊息時,視窗過程首先調用BeginPaint。一般在BeginPaint函數的調用中,如果客戶區的無效地區的背景還未被擦除,則由Windows來擦除。(它使用登入的視窗類別WNDCLASS結構的hbrBackground成員變數中指定的畫刷來擦除背景,上回的注釋1我們提過)

BeginPaint調用使整個客戶區有效,並且返回一個裝置描述表控制代碼,這一傳回值通常被儲存在叫做hdc的變數中。該函數也填入ps結構的欄位(可以回憶一下上一回的注釋1)。

裝置描述表控制代碼在視窗過程中的定義如下:

HDC hdc ;//定義裝置描述表控制代碼變數

然後,程式就可以使用需要裝置描述表控制代碼的TextOut等GDI函數。在視窗的客戶區顯示文字和圖形需要裝置描述表控制代碼,但是從BeginPaint返回的裝置描述表控制代碼不能在用戶端區域之外繪圖。調用EndPaint即可釋放裝置描述表控制代碼。

一般地,處理WM_PAINT訊息的形式如下:

caseWM_PAINT:

  hdc = BeginPaint (hwnd, &ps) ;

         [other program lines]

  EndPaint (hwnd, &ps) ;

  return 0 ;

      我們再來強調一下吧(別怪我囉嗦):BeginPaint調用使整個客戶區有效(阻止WM_PAINT訊息一直發送,見附錄),填充ps結構的欄位,返回的裝置描述表控制代碼。使用這個控制代碼只能在ps結構中的rcPaint欄位規定的地區內繪圖。EndPaint調用可釋放裝置描述表控制代碼。兩個函數必須成對使用,一般只用在處理WM_PAINT訊息中。

 

Windows程式在處理非WM_PAINT訊息時還可以用以下方法獲得裝置描述表控制代碼,當然以下函數調用不會使客戶區中的無效地區變成有效。

方法二:

hdc = GetDC (hwnd) ;
[other program lines]        
ReleaseDC (hwnd, hdc) ;
GetDC函數調用後會返回hwnd參數所指定的視窗的客戶區所對應的裝置描述表控制代碼。可見GetDC調用與BeginPaint的基本區別是,利用從GetDC返回的控制代碼可以在整個客戶區上繪圖。如果hwnd參數設定為NULL,那麼函數會返回整個案頭的裝置描述表控制代碼。當不再需要該裝置環境時,需要調用ReleaseDC函數釋放裝置描述表。
 

方法三:

hdc = GetWindowDC (hwnd) ;

[other program lines]         
ReleaseDC (hwnd, hdc) ;
GetWindowDC返回可以在整個視窗(包括客戶區部分和標題列、菜單、捲軸、架構等非客戶區部分)繪圖的裝置描述表控制代碼,不過此函數很少使用。
 

方法四:

hdc = CreateDC (lpszDriver, lpszDevice, lpszOutput, lpData) ;

       [other program lines] 
DeleteDC (hdc) ;
BeginPaint、GetDC和GetWindowDC獲得的裝置內容都與顯示器上的某個特定視窗(即hwnd)相關。CreateDC是取得裝置描述表控制代碼一個更通用的函數,它甚至可以擷取非顯示器輸出裝置描述表控制代碼。當不再需要該裝置描述表時只可調用DeleteDC函數刪除它。

當然,獲得裝置描述表的函數還有很多,我們就先簡單介紹到這兒,其他類似的函數我們以後遇到再說。

裝置描述表的屬性——我們上回提到過哦

      裝置描述表中包含許多確定GDI函數如何在裝置上工作的當前“屬性”,這些屬性允許傳遞給GDI函數的參數只包含起始座標或者尺寸資訊,而不必包含Windows在裝置上顯示對象時需要的所有其它資訊。例如,上回我們調用TextOut時,我們只需要在函數中給出裝置描述表控制代碼、起始座標、文字和文字的長度。而不必指定字型、文字顏色、文字後面的背景色彩以及字元間距,因為這些屬性都是裝置描述表的一部分。當你想改變這些屬性之一時,您調用一個可以改變裝置描述表中屬性的函數(例如把文字顏色設定成紅色),以後針對該裝置描述表的TextOut調用就可以使用改變後的屬性了(例如可以輸出紅色字型)。

我在此列出如下表,方便大家查閱。

屬性

預設值

相關函數

背景色

WHITE

GetBkColor

SetBkColor

背景模式

OPAQUE

GetBkMode

SetBkMode

位元影像

NONE

CreateBitMap

CreateBitMapIndirect

CreateCompatibleBitmap

SelectObject

畫刷

WHITE_BRUSH

CreateBrushIndirect

CreateDIBPatternBrush

CreateHatchBrush

CreatePatternBrush

CreateSolidBrush

SelectObject

畫刷起始位置

(0,0)

GetBrushOrg

SetBrushOrg

UnrealizeObject

剪裁域

DISPLAY SURFACE

ExcludeClipRect

IntersetClipRect

OffsetClipRgn

SelectClipPath

SelectObject

SelectClipRgn

顏色調色盤

DEFAULT_PALETTE

CreatePalette

RealizePatte

SelectPalette

繪圖方式

R2_COPYPEN

GetROP2

SetROP2

字型

SYSTEM_FONT

CreateFont

CreateFontIndirect

SelectObject

字元間距

0

GetTextCharacterExtra

SetTextCharacterExtra

映射方式

MM_TEXT

GetMapMode

SetMapMode

畫筆

BLACK_PEN

CreatePen

CreatePenIndirect

SelectObject

多邊形填充方式

ALTERNATE

GetPolyFillMode

SetPolyFileMode

縮放模式

BLACKONWHITE

SetStretchBltMode

GetStretchBltMode

文本顏色

BLACK

GetTextColor

SetTextColor

視圖範圍

(1,1)

GetViewportExtEx

SetViewportExtEx

ScaleViewportExtEx

視圖原點

(0,0)

GetViewportOrgEx

   

SetViewportOrgEx

視窗範圍

(1,1)

GetWindowExtEx

SetWindowExtEx

ScaleWindowExtEx

視窗原點

(0,0)

GetWindowOrgEx

OffsetWindowOrgEx

SetWindowOrgEx

一般以Get開頭的函數作用是擷取該屬性值,一般以Set開頭的函數作用是設定該屬性值,若有不太清楚的函數,你就自己動手查吧。

儲存裝置描述表

      通常,在你調用GetDC或BeginPaint時,Windows用預設值建立一個新的裝置描述表,你對屬性所做的一切改變在裝置描述表調用ReleaseDC或EndPaint釋放時,都會丟失。如果你的程式需要使用非預設的裝置描述表屬性,則你必須在每次取得裝置描述表控制代碼時初始化裝置內容:

case WM_PAINT:
    hdc = BeginPaint (hwnd, &ps) ;
          [initialize device context attributes]
          [paint client area of windows]
    EndPaint (hwnd, &ps) ;
    return 0 ;

      雖然在通常情況下這種方法已經很令人滿意了,但是你還可能想要在釋放裝置描述表之後,仍然儲存程式中對裝置描述表屬性所做的改變,以便在下一次調用GetDC和BeginPaint時它們仍然能夠起作用。為此,可在設計視窗類別時,將CS_OWNDC標誌包含為視窗類別的一部分:

wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC ;

      現在,基於這個視窗類別所建立的每個視窗都將擁有自己的裝置描述表,它一直存在,直到視窗被刪除。如果使用了CS_OWNDC風格,就只需初始化裝置描述表一次,可以在處理WM_CREATE訊息處理期間完成這一操作:

case WM_CREATE:
     hdc = GetDC (hwnd) ;
          [initialize device context attributes]       
ReleaseDC (hwnd, hdc) ;

這些屬性在改變之前一直有效。

CS_OWNDC風格影響GetDC和BeginPaint獲得的裝置內容,不影響其它函數獲得的裝置描述表。使用了CS_OWNDC,你仍然應該在退出視窗過程之前釋放裝置描述表。

      某些情況下,你可能想改變某些裝置描述表屬性,用改變後的屬性進行繪圖,然後恢複原來的裝置描述表屬性。要簡化這一過程,可以通過如下調用來儲存裝置描述表的狀態:

int idSaved = SaveDC (hdc) ;
    現在,可以改變一些屬性,在想要回到調用SaveDC前存在的裝置內容時,調用:
RestoreDC (hdc, idSaved) ;
    你可以在調用RestoreDC之前調用SaveDC數次。

大多數程式寫作者以不同的方式使用SaveDC和RestoreDC。然而,更像組合語言中的PUSH和POP指令,當你調用SaveDC時,可以不需要儲存傳回值:

SaveDC (hdc) ;
    然後,你可以更改某些屬性並再次調用SaveDC。要將裝置內容恢複到一個已經儲存的狀態,調用:
RestoreDC (hdc, -1) ;
    這就將裝置描述表恢複到最近由SaveDC函數儲存的狀態中。

 

附錄

小技巧:

在處理WM_PAINT訊息時,為了在更新的矩形外繪圖,可以在調用BeginPaint之前使用如下函數:

InvalidateRect (hwnd, NULL, TRUE) ;
它使整個顯示地區變為無效,並擦除背景。但是,如果最後一個參數等於FALSE,則不擦除背景,原有的東西將保留在原處。

通常這是Windows程式在無論何時收到WM_PAINT訊息而不考慮rcPaint結構的情況下簡單地重畫整個客戶區最方便的方法。例如,如果在客戶區的顯示輸出中包括了一個圓,但是只有圓的一部分落到了無效矩形中,它就僅繪製圓在無效矩形中的部分。這對於畫整個圓來說是無意義的。注意:使用從BeginPaint返回的裝置描述表控制代碼時,Windows不會繪製rcPaint矩形外的任何部分。在BeginPaint調用之前使用上面那個函數,可使rcPaint結構中的無效矩形為整個客戶區,就不愁繪製圓了。

在處理WM_PAINT訊息時,必須成對地調用BeginPaint和EndPaint。如果視窗過程不處理WM_PAINT訊息,則它必須將WM_PAINT訊息傳遞給Windows中DefWindowProc(預設視窗過程)。DefWindowProc以下列代碼處理WM_PAINT訊息:

case WM_PAINT:

            BeginPaint (hwnd, &ps) ;

            EndPaint (hwnd, &ps) ;

           return 0 ;

    這兩個BeginPaint和EndPaint調用之間中沒有任何語句,僅僅使先前無效地區變為有效。但以下方法是錯誤的:

case WM_PAINT:

    return 0 ;   // WRONG !!!

    Windows將一個WM_PAINT訊息放到訊息佇列中,是因為客戶區的一部分無效。如果不調用BeginPaint和EndPaint(或者ValidateRect),則Windows不會使該地區變為有效。若一直保持無效,Windows將會再發送另一個WM_PAINT訊息,且一直發送下去。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.