win32關鍵點(一)

分7部分:

      窗口和消息

      輸出文本

      圖形基礎

      鍵盤

      鼠標

      計時器

      子窗口控制


一 窗口和消息

1 前綴

前綴
 全稱
 釋義
 
CS
 class style
 類風格選項
 
CW
 create windows
 創建窗口選項
 
DT
 draw text
 繪製文本選項
 
IDI
 Icon ID
 圖標ID號
 
IDC
 Cursor ID
 光標ID號
 
MB
 Message Box
 消息框選項
 
SND
 Sound
 聲音選項
 
WM
 Windows Message
 窗口消息
 
WS
 Windows Style
 窗口風格
 


 

2 WPARAM和LPARAM的意義

  在Windows是一種16位系統時,WndProc的第三個參數被定義爲WORD,是一個16位的無符號整數,而第四個參數被定義爲一個LONG,是一個32位有符號整數,所以導致對單詞PARAM(參數)加前綴W和L。

但在32位Windows中,WPARAM被定義爲一個UINT,而LPARAM被定義爲一個LONG,因此窗口過程的這兩個參數都是32位的值。

 

3 新的函數類型

WndProc函數返回一個類型爲LRESULT的值,該值是一個LONG型,32位有符號。

   

WndProc函數被指定爲CALLBACK類型,WinMain函數被指定爲WINAPI類型。這些類型指在Windows本身和用戶的應用程序之間發生的函數調用的特殊調用序列。

 

4 窗口類結構WNDCLASS

有10個域。分別是:

① style:類風格,用於在什麼時候發出窗口變化消息

② cbClsExtra:在類結構保存的窗口結構中預留一些額外空間

      ③ cbWndExtra:在Windows內部保存的窗口結構中預留一些額外空間

      ④ hbrBackground:指定基於這個類創建的窗口背景顏色

      ⑤ hCursor:讀取光標

      ⑥ hIcon:讀取圖標

      ⑦ hInstance:程序的實例句柄

      ⑧ lpfnWndProc:指定處理基於這個窗口類創建的所有窗口的窗口過程

      ⑨ lpszClassName:指定類名

      ⑩ lpszMenuName:指定窗口類菜單

 

5 註冊窗口類RegisterClass

一般在Windows XP及以後都可以很順利的註冊成功。

所以可以只寫RegisterClass(&wndclass);

 

6 創建窗口CreateWindow

   窗口類定義了窗口的一般特徵,調用CreateWindow可以指定有關窗口的更詳細的信息。

hwnd = CreateWindow (szAppName,         // 指定一個窗口類,基於該窗口類創建窗口

                  TEXT ("Hello Win"),   // 這個字符串會出現在標題欄中

                  WS_OVERLAPPEDWINDOW, // 本窗口風格

                  CW_USEDEFAULT,        //窗口左上角的X座標

                  CW_USEDEFAULT,        //窗口左上角的Y座標

                  CW_USEDEFAULT,        //窗口的寬度

                  CW_USEDEFAULT,        //窗口的高度

                  NULL,                   //窗口對象的父窗口句柄

                  NULL,                   //窗口對象的菜單句柄或者子窗口編號

                  hInstance,                 //當前進程的實例句柄

                  NULL) ;                  //窗口對象的參數指針句柄

 

創建窗口返回的是窗口句柄。

 

7 顯示窗口

窗口創建成功後,系統將在內存中爲其分配一塊內存,但是此時窗口並未顯示在顯示器上,所以需要使用兩個調用。

① ShowWindow(窗口句柄,iCmdShow);

其中的第二個參數用於確定如何兒子屏幕上顯示窗口,是最小化還是常規還是最大化。

 

② UpdateWindow(窗口句柄)

調用上句將導致客戶區被繪製。它通過給窗口過程發送一個WM_PAINT消息來做到這一點。

 

8 消息循環

調用UpdateWindow之後,窗口就出現在顯示器上。

Windows爲當前運行的每個Windows程序維護一個“消息隊列”。在發生事件的時候,Windows將事件轉換爲一個“消息”,並將消息放入程序的消息隊列中。

 

程序通過執行一個叫做“消息循環”的代碼從消息隊列中取出消息。

 

while (GetMessage(&msg, NULL, 0, 0))

          {

                 TranslateMessage(&msg);

                 DispatchMessage(&msg);

          }

   

其中msg是一個類型爲MSG的結構,MSG結構在WINUSER.H中定義如下:

typedef struct tagMSG {

   HWND      hwnd;

   UINT        message;

   WPARAM    wParam;

   LPARAM     lParam;

   DWORD     time;

   POINT       pt;

} MSG, *PMSG

 

其中,hwnd 是消息發向的窗口句柄。

     message 是消息標識符,以WM_開頭。

     wParam 一個32位的消息參數。

     lParam 一個32位的消息參數。

     time 消息放入消息隊列的時間。

     pt 消息放入消息隊列時鼠標的座標。

 

消息循環以GetMessage調用開始,它從消息隊列中取出一個消息,GetMessage(&msg, NULL, 0, 0)這一調用傳給Windows一個指向名爲msg的MSG結構的指針。其餘三個參數設置爲NULL或0,表示程序接收自己創建的所有窗口的所有消息。

 

只要從消息隊列中取出的消息的message域不爲WM_QUIT,GetMessage就返回一個非0值,while循環就可以繼續。

TranslateMessage(&msg);將msg結構傳給Windows,進行一些鍵盤轉換。

DispatchMessage(&msg);將msg結構傳給Windows,然後Windows將裏面的消息發給相應的窗口過程進行處理。處理後,WndProc返回到Windows,Windows返回到程序,程序繼續下一個while循環。

 

9 窗口過程WndProc

實際的動作發生在窗口過程中。窗口過程確定了在窗口的客戶區顯示什麼,以及怎麼處理用戶輸入。

窗口過程是命名爲WndProc的函數。(也可以其他不衝突的名字)

一個Windows程序可以包含多個窗口過程。

一個窗口過程總是與調用RegisterClass註冊的特定窗口類相關聯。

CreateWindow函數根據特定的窗口類創建一個窗口,返回該窗口的句柄。

但是基於一個窗口類可以創建多個窗口。

 

1程序    包括  n個窗口過程

1窗口過程關聯  1窗口類

1窗口類  創建  n個窗口

CreateWindows根據窗口類創建一個窗口。

 

窗口過程總是聲明成如下形式:

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

這4個參數跟MSG結構的前4個域是相同的。

第一個參數:接收消息的窗口句柄。

第二個參數:消息類型,標識消息的數字

最後兩個參數:32位的消息參數。

 

程序通常不直接調用窗口過程,而是由Windows調用窗口過程。

 

10 窗口過程處理消息

窗口過程接收的每個消息均是用一個數值來標識的,也就是傳給窗口過程的message參數。

窗口過程處理消息時,必須返回0.窗口過程不予處理的所有消息應該被傳給名爲DefWindowsProc的Windows函數。

用switch語句來處理不同消息,消息以WM_開頭。

 

11 WM_CREATE消息

當Windows在處理CreateWindow函數時,窗口過程就會接收到WM_CREATE消息。

通常,窗口過程在WM_CREATE處理期間進行一次窗口初始化。

 

12 WM_PAINT消息

當窗口客戶區域的一部分或全部變成“無效”時,必須進行刷新,WM_PAINT將通知程序。

在最初創建窗口的時候,整個客戶區都是無效的,因爲程序還沒有在窗口上畫任何東西。在調用UpdateWindow時,通常會觸發第一個WM_PAINT消息,指示窗口過程在客戶區域上畫一些東西。

 

在改變程序窗口大小後,客戶區也會變得無效,至於怎麼變得無效由CS_引導的類風格選項確定。

 

對WM_PAINT的處理幾乎總是從一個BeginPaint調用開始,以一個EndPaint結束。

hdc = BeginPaint(hwnd, &pt);

do something;(如GetClientRect(hwnd, &rect);)

EndPaint(hwnd, &pt);

 

hwnd是要刷新的窗口的窗口句柄。

pt是指向類型爲PAINTSTRUCT的結構指針。

 

在BeginPaint調用中,如果客戶區域的背景還未被擦除,就由Windows來擦除。然後使用註冊窗口類的WNDCLASS結構中的hbrBackground域中第一的刷子來刪除背景。

BeginPaint調用使整個客戶區有效,並返回一個“設備描述表句柄”。設備描述表是指物理輸出設備及其驅動程序。可以利用該“設備描述表句柄”在客戶區域顯示文本和圖形。

EndPaint調用釋放設備描述表句柄。

 

GetClientRect(hwnd, &rect);

第一個參數:程序的窗口句柄;

第二個參數:指向RECT類型的rectangle結構。該結構有4個LONG域,標識客戶區域的尺寸。

當改變窗口大小時,WndProc通過調用GetClientRect來獲取變化後的窗口大小,重新繪製客戶區。

 

13 WM_DESTROY消息

   當用戶點擊關閉按鈕時發生。

程序可以通過調用PostQuitMessage以標準方式響應WM_DESTROY消息;

PostQuitMessage(0);

該函數在程序的消息隊列插入一個WM_QUIT消息。

GetMessage對於除了WM_QUIT消息之外的從消息隊列中取出的所有消息都返回非0值。而當GetMessage取到一個WM_QUIT消息時,返回0.

 

14 關閉程序時的消息傳遞

① 用戶點擊關閉按鈕

② 產生WM_SYSCOMMAND消息;

③ 產生WM_CLOSE消息響應WM_SYSCOMMAND;

④ 產生WM_DESTROY消息響應WM_CLOSE;

⑤ 產生WM_QUIT消息響應WM_DESTROY。

 

15 進隊消息和不進隊消息

消息能夠分爲:進隊消息和不進隊消息。

進隊消息是由Windows放入程序消息隊列中的。在程序的消息循環中,重新返回並分配給窗口過程。

不進隊消息在Windows調用窗口時直接發送給窗口過程。

 

也就是說,進隊消息發送給消息隊列,不進隊消息發送給窗口過程。

在任何情況下,窗口過程都將獲得窗口所有的消息。窗口過程是窗口的消息中心。

 

進隊消息基本上是用戶輸入的結果,還包括時鐘消息、刷新消息、退出消息。

不進隊消息基本上是來自調用特定的Windows函數。

 

 

二 輸出文本

16 有效矩形和無效矩形

窗口過程一旦接受到WM_PAINT消息之後,就準備更新整個客戶區,但往往只需更新一個較小的區域。這個區域就稱爲“無效區域”。正是客戶區內存在無效區域,才提示Windows將一個WM_PAINT消息放入消息隊列。

 

Windows內部爲每個窗口保存一個“繪圖信息結構”,這個結構包含了包圍無效區域的最小矩形的座標以及其他信息,這個矩形就叫做“無效矩形”。

如果在窗口過程處理WM_PAINT消息之前,客戶區又有一個區域變爲無效,那麼Windows計算出一個包圍兩個無效區域的新的無效矩形,並將這個變化後的信息放在繪製信息結構中。

一個消息隊列在一個時刻只能有一個WM_PAINT消息在隊列中。

 

窗口過程可以調用InvalidateRect使客戶區變爲無效。如果消息隊列包含一個WM_PAINT消息,那麼Windows將計算出新的無效矩形;否則,就在消息隊列中添加一個WM_PAINT消息。

 

在處理WM_PAINT消息期間,窗口過程在調用了BeginPaint之後,整個客戶區就會變得有效。

程序也可以顯式調用ValidateRect函數使客戶區內的任意矩形區域變得有效。如果這條調用使整個客戶區都有效,那麼將在當前消息隊列中刪除WM_PAINT消息。

 

17 設備描述表

要在窗口的客戶區繪圖,可以使用Windows的圖形設備接口GDI函數。

設備描述表DC是GDI內部保存的數據結構。

設備描述表與特定的顯示設備有關。

設備描述表中的有些值是圖形化的“屬性”,如指出顏色、背景色、座標映射方式等。

 

當程序要繪圖時,必須先獲取設備描述表句柄。在獲取了該句柄之後,Windows用默認的屬性值填充設備描述表結構的內部各域。

當程序在客戶區繪圖完畢後,必須釋放設備描述表句柄。句柄被釋放後不再有效,也不再使用。程序必須在處理單個消息期間獲取和釋放句柄。

 

18 獲取設備描述表句柄的方法之一

在使用WM_PAINT消息時,使用這種方法。它涉及到BeginPaint和EndPaint兩個函數。

在處理WM_PAINT消息時,窗口過程首先調用BeginPaint。BeginPaint函數一般在準備繪製時導致無效區域的背景被擦除。BeginPaint返回的值是設備描述表句柄,這一返回值通常被保持在叫做hdc的變量中。

HDC hdc;

HDC數據類型定義爲32位的無符號數。

然後,程序就可以使用需要設備描述表句柄的GDI函數了。

調用EndPaint即可釋放設備描述表句柄。

 

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

case WM_PAINT:

   hdc = BeginPaint(hwnd, &ps);

   使用GDI函數

   EndPaint(hwnd, &ps);

   return 0;

 

處理WM_PAINT消息時,必須成對地調用BeginPaint和EndPaint。

 

19 繪圖信息結構

Windows爲每一個窗口保存一個繪圖信息結構。這就是PAINTSTRUCT,定義如下:

 

typedef struct tagPAINTSTRUCT {

   HDC        hdc;          

   BOOL       fErase;        

   RECT       rcPaint;

   BOOL       fRestore;

   BOOL       fIncUpdate;

   BYTE       rgbReserved[32];

} PAINTSTRUCT

 

在程序調用BeginPaint時,Windows填充該結構的各個字段。用戶程序只需要使用前三個字段。

hdc是設備描述表句柄。

 

fErase通常被標識爲FLASE,這意味着Windows已經擦除了無效矩形的背景。

如果程序通過調用Windows函數InvalidateRect使客戶區中的矩形失效,那麼該函數的最後一個參數會指定fErase的值。如果指定0,那麼在稍後的PAINTSTRUCT裏面的fErase會被設置爲TRUE。

 

rcPaint是RECT結構,定義了無效矩形的邊界。RECT結構中的left、top、right、bottom以像素點爲單位。此時,Windows將繪圖操作限制在此RECT結構定義的矩形範圍內,如果要在無效矩形外繪圖,應該在調用BeginPaint之前,使用如下調用:

InvalidateRect(hwnd, NULL, TRUE);

它將使整個客戶區無效,並擦除背景。

 

20獲取設備描述表句柄的方法之二

要得到窗口客戶區的設備描述表句柄,可以調用GetDC來獲取句柄。在使用完後調用ReleaseDC;

hdc = GetDC(hwnd);

使用GDI函數

ReleaseDC(hwnd, hdc);

GetDC和ReleaseDC函數必須成對地使用。

GetDC返回的設備描述表句柄具有一個剪取矩形,等於整個客戶區。

GetDC不會使任何無效區域變爲有效,要是整個客戶區有效,需要調用:

ValidateRect(hwnd, NULL);

 

一般可以調用GetDC和ReleaseDC來對鍵盤消息、鼠標消息作出反應。

 

21 TextOut細節

TextOut是用於顯示文本的最常用的GDI函數。語法是:

TextOut(hdc, x, y, psText, iLength);

 

第一個參數:設備描述表句柄,既可以是GetDC的返回值,也可以是BeginPaint的返回值。

第二個參數:定義客戶區內字符串的開始位置的水平座標。

第三個參數:定義客戶區內字符串的開始位置的垂直座標。

第四個參數:指向要輸出的字符串的指針。

第五個參數:字符串中字符的個數。如果psText中的字符是Unicode的,那麼串中的字節數就是iLength值的兩倍。

 

設備描述表還定義了一個剪取區域。

對於從GetDC獲取的設備描述表句柄,默認的剪取區是整個客戶區。

對於從BeginPaint獲取的設備描述表句柄,默認的剪取區是無效區域。

Windows不會在剪取區域之外的任何位置顯示字符串。

 

22 字符大小

要用TextOut顯示多行文本,就必須確定字體的字符大小,可以根據字符的高度來定位字符的後續行,以及根據字符的寬度來定位字符的後續列。

系統字體的字符高度和平均寬度取決於視頻顯示器的像素大小。

 

程序可以調用GetSystemMetrics函數來確定關於用戶界面構件大小的信息。

程序可以調用GetTextMetrics函數來確定字體大小。

metric是度量的意思。

 

TEXTMETRIC的結構:

typedef struct tagTEXTMETRIC

{

   LONG       tmHeight;

   LONG       tmAscent;

   LONG       tmDescent;

   LONG       tmInternalLeading;

   LONG       tmExternalLeading;

   LONG       tmAveCharWidth;

   LONG       tmMaxCharWidth;

   其他域

} TEXTMETRIC, *PTEXTMETRIC;

 

要使用GetTextMetrics函數,需要先定義一個通常被稱爲tm的結構變量:

TEXTMETRIC tm;

在需要確定文本尺寸時,先要獲取設備描述表句柄,再調用GetTextMetrics:

hdc = GetDC(hwnd);

GetTextMetrics(hdc, &tm);

操作;

ReleaseDC(hwnd,hdc);

 

23 文本尺寸

字體的縱向大小由5個值確定:

① tmHeight,等於tmAscent加上tmDescent。這兩個值表示了基線上下字符的最大縱向高度。

② tmAscent,基線以上的高度

③ tmDescent,基線以下的高度

④ tmInternalLeading,重音號和字符之間的距離,如ü中的u和兩點的距離。

⑤ tmExternalLeading,一般用於多行文本間行距的調整。

字符的橫向大小由2個值確定:

① tmAveCharWidth,小寫字母加權平均寬度。

② tmMaxCharWidth,字體中最寬字符的寬度。

對於等寬字體,tmAveCharWidth和tmMaxCharWidth這兩個值相等。

大寫字母的平均寬度比較複雜,如果:

① 字體是等寬字體,那麼大寫字母的平均寬度等於tmAveCharWidth。

② 字體是變寬字體,那麼大寫字母的平均寬度等於tmAveCharWidth*1.5。

 

判斷字體是否是變寬字體,可以通過TEXTMETRIC結構中的tmPitchAndFamily域的低位判斷,如果低位是1,那麼是變寬字體,如果是0,那麼是等寬字體。

大寫字母寬度 = (tm.tmPitchAndFamily & 1 ? 3 : 2) / 2 * 小寫字母寬度

 

24 格式化文本

在一次Windows對話期間,系統字體的大小不會改變,因此在程序運行過程中,只需要調用一次GetTextMetric。最好是在窗口過程中處理WM_CREATE消息時進行此調用。

假設要編寫一個Windows程序,在客戶區顯示多行文本,這需要先獲取字符寬度和高度。可以在窗口過程內定義兩個變量來保存字符寬度和總的字符高度。

case WM_CREATE:

  hdc = BeginPaint(hwnd, &pt);

  GetTextMetric(hdc, &tm);

  cxChar = tm.tmAveCharWidth;                                 小寫字母寬度

  cyChar = tm.Height + tm.tmExternalLeading;                     字母高度

  cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) / 2 * tm.tmAveCharWidth; 大寫字母寬度

  EndPaint(hwnd, &pt);

  return 0;

 

25 客戶區的大小

窗口最大化之後的客戶區大小,可以通過以SM_CXFULLSCREEN和SM_CYFULLSCREEN爲參數調用GetSystemMetric來獲得。

要確定客戶區的大小,最好的方法是在窗口過程處理WM_SIZE消息。在窗口大小改變時,就會產生WM_SIZE消息。傳給窗口過程的lParam參數的低位字中包含客戶區的寬度x,高位字中包含客戶區的高度y。要保存這些尺寸,可以定義兩個int型變量來保存。

static int cxClient,cyClient;

然後在WM_SIZE消息處理中:

case WM_SIZE:

   cxClient = LOWORD(lParam);

   cyClient = HIWORD(lParam);

   return 0;

 

用cyClient/cyChar可以得到客戶區可以顯示的文本總行數。

 

客戶區大小的另外一種獲取方法就是使用:

BOOL GetClientRect(HWND hWnd,      // handle to window
               LPRECT lpRect  // address of structure for client coordinates

獲取窗口的大小,使用:

BOOL GetWindowRect(HWND hWnd,      // handle to window
                  LPRECT lpRect  // address of structure for window coordinates);

獲取屏幕大小:

方式一:最大化當前窗口後,窗口大小就是屏幕大小。

方式二:使用 GetDeviceCaps(HDC hdc, int nIndex ),參看 34 設備的大小。

 

26 滾動條的範圍和位置

每個滾動條都有一個相關的範圍和位置。這是一對整數。當滾動框在滾動條的頂部(左部)時,滾動框的位置是範圍的最小值;在滾動條的底部(右部)時,滾動框的位置是範圍的最大值。

在默認情況下,滾動條的範圍是0~100,但將範圍改變爲更方便於程序的數值也是很容易的:

SetScrollRange(hwnd, iBar, iMin, iMax, bRedraw);

其中hwnd爲該窗口的句柄。

   iBar爲SB_VERT或SB_HORZ。

   iMin和iMax爲範圍。

   bRedraw,如果要Windows根據新範圍重繪滾動條,則設置爲TRUE。

 

滾動框的位置不是連續的,而是離散的整數值。

可以使用SetScrollPos在滾動條範圍內設置新的滾動框位置:

SetScrollPos(hwnd, iBar, iPos, bRedraw);

參數iPos是新位置,必須在iMin至iMax的範圍內。

 

Windows提供了類似的函數GetScrollRange和GetScrollPos來獲取滾動條的當前範圍和位置。

 

27 滾動條消息

在用鼠標單擊滾動條或者拖動滾動框時,Windows都給窗口過程發生WM_VSCROLL或WM_HSCROLL消息。在滾動條上的每個鼠標動作都至少產生兩個消息,一個在按下鼠標鍵時產生,一個在釋放鼠標鍵時產生。

WM_VSCROLL和WM_HSCROLL也帶有wParam和lParam消息參數。

lParam只用於作爲子窗口而創建的滾動條(通常在對話框內)。

wParam消息參數被分爲一個低位字和一個高位字。

低位字是一個數值,指出了鼠標對滾動條進行的操作。這個數值被看作一個“通知碼”。通知碼以SB開頭。

#define SB_LINEUP          0

#define SB_LINELEFT        0

#define SB_LINEDOWN       1

#define SB_LINERIGHT       1

#define SB_PAGEUP          2

#define SB_PAGELEFT        2

#define SB_PAGEDOWN       3

#define SB_PAGERIGHT       3

#define SB_THUMBPOSITION  4

#define SB_THUMBTRACK    5

#define SB_TOP              6

#define SB_LEFT             6

#define SB_BOTTOM          7

#define SB_RIGHT            7

#define SB_ENDSCROLL       8

 

當把鼠標的光標放在滾動框上並按住鼠標鍵時,就產生SB_THUMBPOSITION和SB_THUMBTRACK消息。

當wParam的低位字是SB_THUMBTRACK時,wParam的高位字是用戶在拖動滾動框時的當前位置。

當wParam的低位字是SB_THUMBPOSITION時,wParam的高位字是用戶釋放鼠標後滾動框的最終位置。

 

28 滾動條信息函數

滾動條文檔指出SetScrollPos、SetScrollRange、GetScrollPos、GetScrollRange函數是過時的。

在Win32 API中,升級了2個滾動條函數,稱作SetScrollInfo和GetScrollInfo。這些函數完成上述4個函數的全部功能,並增加了2個新特性。

第一個功能設計滾動框的大小。滾動框的大小稱作頁面大小。算法是:

滾動框大小 / 滾動長度 ≈ 頁面大小 / 範圍 ≈ 顯示的文檔數量 / 文檔的總大小

可以使用SetScrollInfo來設置頁面大小。

 

第二個功能是GetScrollInfo函數,它可以獲取32位的範圍值。

 

SetScrollInfo和GetScrollInfo函數的語法是:

SetScrollInfo(hwnd, iBar, &si, bRedraw);

GetScrollInfo(hwnd, iBar, &si);

 

iBar參數是SB_VERT或SB_HORZ。

bRedraw可以是TRUE或FALSE,指出了是否要Windows重新繪製計算了新信息後的滾動條。

兩個函數的第三個參數是SCROLLINFO結構,定義爲:

typedef struct tagSCROLLINFO

{

   UINT   cbSize;

   UINT   fMask;

   int      nMin;

   int      nMax;

   UINT   nPage;

   int      nPos;

   int      nTrackPos;

}  SCROLLINFO

 

在程序中,可以定義如下的SCROLLINFO結構類型:

SCROLLINFO si;

在調用SetScrollInfo或GetScrollInfo函數之前,必須將cbSize自動設置爲結構的大小:

si.cbSize = sizeof(si);或si.cbSize = sizeof(SCROLLINFO);

 

fMask:把fMask字段設置爲以SIF前綴開頭的一個或多個標識,來獲取或設置裏面的結構中域的值。

① SIF_RANGE:用於獲取或設置滾動條的範圍

② SIF_POS:用於獲取或設置滾動框的位置

③ SIF_PAGE:用於獲取或設置滾動條的頁面大小

④ SIF_TRACKPOS:用於獲取或設置滾動框移動時的位置

 

 

三 圖形基礎

29 GDI基礎

圖形設備接口GDI是Windows的子系統,它負責在視頻顯示器和打印機上顯示圖形。

Windows NT中的圖形主要由GDI32.DLL動態鏈接庫輸出的函數來處理。

GDI的主要目的之一是支持與設備無關的圖形。

 

圖形輸出設備分爲兩大類:光柵設備和矢量設備。

大多數PC機顯示器、打印機都是光柵設備。

繪圖儀是矢量設備。

 

組成GDI的函數可以分爲這樣幾類:

① 獲取(或重建)和釋放(或清除)設備描述表的函數;

② 獲取有關設備描述表信息的函數;

③ 繪圖函數;

④ 設置和獲取設備描述表參數的函數;

⑤ 使用GDI對象的函數。

 

30 GDI圖元

在屏幕或打印機上顯示的圖形類型本身可以被分爲幾類,通常被稱爲“圖元”。

① 直線和曲線

② 填充區域

③ 位圖:位圖是位的矩形數組,位對應於顯示設備上的像素,它們是光柵圖形的基本工具。GDI支持兩種類型的位圖——老的“設備有關”位圖,新的“設備無關”位圖。

④ 文本

 

 


 

31 GDI其他方面

① 映射模式和變化;

② 元文件:元文件是以二進制形式存儲的GDI命令的集合。元文件主要用於通過剪貼板傳輸矢量圖形表示。

③ 區域:區域是形狀任意的複雜區;

④ 路徑:路徑是GDI內部存儲的直線和曲線的集合;

⑤ 剪裁:繪圖可以限制在客戶區的某一部分中,這就是剪裁。剪裁通常是通過區域或者路徑定義的。

⑥ 調色板:定製調色板通常限於顯示256色的顯示器。Windows僅保留這些色彩之中的20種供系統使用,但可以改變其他236種色彩。

⑦ 打印

 

32 進一步探討設備描述表

想在一個圖形輸出設備上繪圖時,首先必須獲得一個設備描述表的句柄。將句柄返回給程序時,Windows就給了用戶使用設備的權限。然後在GDI函數中將該句柄作爲一個參數,向Windows標識想在其上進行繪圖的設備。

(1)獲取設備描述表句柄

如果在處理一條消息時獲取了設備描述表句柄,應該在退出窗口函數之前釋放它。

獲取設備描述表句柄的幾種方法:

① 在處理WM_PAINT消息時,使用BeginPaint和EndPaint調用

hdc = BeginPaint(hwnd, &ps);

GDI操作

EndPaint(hwnd, &ps);

注:變量ps是類型爲PAINTSTRUCT的結構,該結構的hdc字段是BeginPaint返回的設備描述表句柄。PAINTSTRUCT結構包含了一個名爲rcRect的RECT結構,該結構定義了包圍窗口無效範圍的矩形。使用從BeginPaint獲得的設備描述表句柄,只能在這個區域內繪圖。BeginPaint調用使這個區域有效。

 

② 可以在處理非WM_PAINT消息時獲取設備描述表句柄

hdc = GetDC(hwnd);

GDI操作

ReleaseDC(hwnd, hdc);

注:這個設備描述表適用於窗口句柄爲hwnd的客戶區。這個調用可以在整個客戶區上繪圖。

 

③ Windows程序還可以獲取適用於整個窗口的設備描述表句柄

hdc = GeWindowstDC(hwnd);

GDI操作

ReleaseDC(hwnd, hdc);

注:這個設備描述表除了客戶區之外,還包括窗口的標題欄、菜單、滾動條和框架。如果要使用該函數,必須捕獲WM_NCPAINT消息。

 

④ 獲取整個屏幕的設備描述表句柄

hdc = CreateDC(TEXT(“DISPLAY”), NULL, NULL, NULL);

原型是:hdc = CreateDC(pszDriver, pszDevice, pszOutput, pData);

       GDI操作

       DeleteDC(hdc);

 

⑤ 如果只需要獲取關於某設備描述表的一些信息,而並不進行任何繪畫,在這種情況下,可以使用CreateIC來獲取一個“信息描述表”的句柄,其參數和CreateDC一樣。

 

⑥ 一個設備描述表通常是指一個物理顯示設備。通常,需要獲取有關該設備的信息,其中包括顯示器的顯示尺寸和色彩範圍。可以通過GetDeviceCaps函數來獲取這些信息。

iValue = GetDeviceCaps(hdc, iIndex);

參數iIndex的取值爲WINGDI.H頭文件中定義的29個標識符之一。

 

33 用TextOut輸出整型的方法

設一開始有整型:int i = 100;

要用TextOut函數將i輸出,需要用到三個函數:

① wsprintf

② TEXT宏

③ TextOut

 

首先得先說明下wsprintf的原型:

int wsprintf(LPTSTR lpOut, LPCTSTR lpFmt,...);

第一個參數:緩衝區,是一個字符數組,一般定義爲TCHAR型。

第二個參數:格式字符串,因爲第一個參數是TCHAR類型,一定要和TEXT宏聯合使用,這樣才能在不同的編譯環境下都可以順利編譯。

後續參數:要輸出的的整型變量。

 

針對第一個參數:要定義一個TCHAR的字符數組作爲緩衝區。

TCHAR szBuffer[10]; //足夠大就行了

針對第二個參數,需要使用到TEXT宏。

 

TEXT宏的原型:

TEXT(LPTSTR string //ANSI or Unicode string);

用來處理要轉換的整型,具體用法是:

TEXT(“%d”);

 

那麼上述的兩個調用應該寫成:

int iLength = 0; //用來保存字符串中的字符個數;

iLength = wsprintf(szBuffer, TEXT(“%d”), i);

上述語句的作用是:將i存進szBuffer中,返回szBuffer存有的字符個數到iLength中。

 

TextOut的原型是:

TextOut(hdc, x, y, psText, iLength);

第一個參數是設備描述表句柄;

第二個參數是輸出的文本的x座標;

第三個參數是輸出的文本的y座標;

第四個參數是是指向要輸出的字符串的指針;

第五個參數是字符串中的字符個數;

那麼TextOut函數應該寫成:

TextOut(hdc, x, y, szBuffer, iLength);

 

34 設備的大小

使用GetDeviceCaps函數能獲取有關輸出設備物理大小的信息。

對於打印機,用“每英寸的點數dpi”表示分辨率。

對於顯示器,用水平和垂直的總的像素數來表示分辨率。

 

用“像素大小”或“像素尺寸”表示設備水平或垂直顯示的總像素數。

用“度量大小”或“度量尺寸”表示以每英寸或毫米爲單位的顯示區域的大小。

像素大小 / 度量大小 = 分辨率

 

使用SM_CXSCREEN和SM_CYSCREEN參數從GetDeviceCaps得到像素大小;

使用HORZSIZE和VERTSIZE參數從GetDeviceCaps得到度量大小;

兩者相除就可以得到水平分辨率和垂直分辨率。

如果設備的水平分辨率和垂直分辨率相等,就稱該設備具有“正方形像素”。

   因爲整個屏幕的度量大小是固定的,所以可以根據分辨率調整水平或垂直顯示的像素數。如果分辨率小,那麼“像素大小”也就小,也就是說,總像素數少了,那麼每個像素的尺寸也就變得大些。

 

35 字體的大小

現在討論字體的大小問題,這裏不是說字號,而是說字體顯示的dpi值。Windows系統默認是每英寸96點,所另外一種選擇,就是每英寸120點。

我們在調整分辨率的時候,從小分辨率變化到大分辨率時,會覺得圖標的文字變小,那是因爲在大分辨率下,每個像素的面積變小,假設一個字需要100個像素來顯示,那麼從小分辨率變化到大分辨率時,字的總面積就變小了,所以字的大小也就發生變化,而這一變化是字體的大小變化,而不是該字的字號發生變化。

在傳統的排版中,字體的字母大小由“磅”表示。1磅≈1/72英寸,在計算機排版中1磅正好爲1/72英寸。

理論上,字體的磅值是從字體中最高的字符頂部到字符下部的字符底部的距離,其中不包括重音號。根據TEXTMETRIC結構,字體的磅值等於tmHeight – tmInternalLeading。

 

36 關於色彩

“全色”視頻顯示器的分辨率是每個像素24位:8位紅色、8位綠色、8位藍色。

“高彩色”顯示分辨率是每個像素16爲:5位紅色、6位綠色、5位藍色。

 

顯示256種顏色的視頻適配器每個像素需要8位。然而這些8位的值一般由定義實際顏色的調色板表組織。

 

使用GetDeviceCaps可以使程序員確定視頻適配器的存儲組織,以及能夠表示的色彩數目。

這個調用返回色彩平面的數目:iPlanes = GetDeviceCaps(hdc, PLANES);

這個調用返回每個像素的色彩位數:iBitsPixel = GetDeviceCaps(hdc, BITSPIXEL);

 

大多數彩***形顯示設備要麼使用多個色彩平面,要麼每像素有多個色彩位,但是不能同時二者兼用;即這兩個調用必須有一個返回1.(一般都是第一個返回1)。

 

在大多數GDI函數調用中,使用COLORREF值(32位)來表示一種色彩。

31
 …
 24
 23
 …
 16
 15
 …
 8
 7
 …
 0
 
0
 藍
 綠
 紅
 

理論上,COLORREF可以指定2的24次方或1600萬種色彩。

這個無符號長整數常常稱爲一個“RGB色彩”。在使用RGB(r, g, b);宏時注意參數的順序是紅、綠、藍。而在無符號長整數中,由高位到低位是0、藍、綠、紅。

當三個參數都是0時,表示黑色,當三個參數都是255時,表示白色。

黑色 = RGB(0,0,0) = 0x00000000

白色 = RGB(255, 255, 255) = 0x00FFFFFF

 

37 保存設備描述表

通常,在調用GetDC或BeginPaint時,Windows會用默認值創建一個新的設備描述表,對設備描述表其屬性所做的一切修改在調用ReleaseDC或EndPaint被釋放掉。

如果需要使用非默認的設備描述表屬性,則必須在每次獲取設備描述表句柄時初始化設備描述表。

如果需要在釋放設備描述表之後,仍然保存程序中對設備描述表所做的改變,以便在下一次調用GetDC和BeginPaint時它們仍起作用。則應該在窗口類那將CS_OWNDC標誌包含進窗口類風格中。

wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

現在,基於這個窗口類所創建的每個窗口都將擁有自己的設備描述表,它一直存在,直到窗口被刪除。

如果使用了CS_OWNDC風格,就只需初始化設備描述表一次,可以在處理WM_CREATE消息期間完成這一操作。

CS_OWNDC風格隻影響GetDC和BeginPaint獲得的設備描述表,不影響其他函數獲得的設備描述表,如GetWindowDC獲得的設備描述表。

在某些情況下,可以需要改變某些設備描述表,用改變後的屬性進行繪圖,然後又要恢復回改變前的屬性。這時,可以通過如下調用來保存設備描述表的狀態。

保存:int idSaved = 0; idSaved = SaveDC(hdc);

恢復:RestoreDC(hdc, idSaved);

也可以不保存SaveDC的返回值,這時候如果要恢復,就只能恢復到最近保存的狀態,RestoreDC(hdc, -1);

 

38 寫像素

寫像素SetPixel(hdc, x, y, crColor);其中:

hdc是設備描述表句柄;

x, y是像素點的座標;

crColor是要設置的顏色,一般可以用RGB(r, g, b)設置。

 

39 線條

幾種畫線函數:

① LineTo:畫直線

② Polyline和PolylineTo:畫一系列相連的直線

③ PolyPolyline:畫多組相連的線

④ Arc和ArcTo和AngleArc:畫橢圓線

⑤ PolyBezier和PolyBezierTo:畫貝塞爾線條

⑥ PolyDraw:畫一系列相連的線以及貝塞爾線條

 

幾種填充函數:

① Rectangle:畫矩形

② Ellipse:畫橢圓

③ RoundRect:畫帶圓角的矩形

④ Pie:畫橢圓的一部分,使其看起來像一個扇形

⑤ Chord:畫橢圓的一部分,使其看起來像弓形

⑥ Polygon:畫多邊形

⑦ PolyPolygon:畫多個多邊形

 

設備描述表的5個屬性影響着用這些函數所畫線條的外觀:

① 當前畫筆的位置;

② 畫筆;

③ 背景方式;

④ 背景色;

⑤ 繪圖模式。

 

畫一條直線,必須調用2個函數,第一個函數指定了線的開始點座標,第二個函數指出了線的終點座標:

MoveToEx(hdc, x1, y1, NULL);

LineTo(hdc, x2, y2);

 

MoveToEx不會畫線,只是設置了設備描述表的“當前位置”屬性。然後LineTo函數從當前的位置到它所指定的點畫一直線。在默認的設備描述表中,當前位置最初是在點(0,0)。

MoveToEx最後一個參數是指向POINT結構的指針。從該函數返回後,POINT結構的x和y字段指出了之前的“當前位置”,如果不需要這個信息,直接填NULL。

 

如果需要獲取當前位置,先定義一個POINT的結構變量pt,然後通過下面的調用:

GetCurrentPositionEx(hdc, &pt);

 

幾個函數的原型:

Rectangle(hdc, xLeft, yTop, xRight, yBottom);

Ellipse(hdc, xLeft, yTop, xRight, yBottom);

RoundRect(hdc, xLeft, yTop, xRight, yBottom, xCorner, yCorner);

Chord(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);

      Pie(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);

      Arc(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);

 

一個二維的貝塞爾線條由4個點定義——兩個端點和兩個控制點。曲線的控制點固定,將曲線從兩個端點間的直線處拉伸構造麴線。

 

40 使用畫筆

調用任何畫筆函數時,Windows使用設備描述表中當前選中的“畫筆”來畫線。畫筆決定線的色彩、寬度、線型。線型可以是實線、點劃線、虛線,默認設備描述表中畫筆是BLACK_PEN,一個像素寬,實線。

Windows提供三種現有畫筆,分別是:BLACK_PEN, WHITE_PEN和NULL_PEN。

Windows使用句柄來引用畫筆。用HPEN的類型定義,即畫筆的句柄。

HPEN hPen;

 

調用GetStockObject,可以獲得現有畫筆的句柄。

hPen = GetStockObject(WHITE_PEN);

 

調用SelectObject將畫筆選進設備描述表。

SelectObject(hdc,hPen);

 

SelectObject的返回值是選進前設備描述表的畫筆句柄。

 

使用CreatePen或CreatePenIndirect創建一個“邏輯畫筆”,這僅僅是對畫筆的描述。這些函數返回邏輯畫筆的句柄,然後調用SelectObject將畫筆選進設備描述表,之後纔可以使用新的畫筆來畫線。

在任何時候,只能有一種畫筆選進設備描述表。

在釋放設備描述表或在選擇了另一種畫筆到設備描述表中之後,就可以調用DeleteObject來刪除所創建的邏輯畫筆。

邏輯畫筆是一種“GDI對象”,GDI對象有六種:畫筆、刷子、位圖、區域、字體、調色板。

CreatePen的原型是:

HPEN CreatePen(iPenStyle, iWidth, crColor);

 

iPenStyle參數確定畫筆是實線、虛線還是點線。

iWidth參數確定線寬,如果iPenStyle不是實線,且iWith大於1,那麼畫筆將變成實線。

crColor是RGB顏色。

 

獲取當前畫筆句柄:

hPen = GetCurrentObject(hdc, OBJ_PEN);

 

還可以建立一個邏輯畫筆LOGPEN結構,調用CreatePenIndirect來創建畫筆。

LOGPEN logpen;

此結構有三個成員:UINT lopnStyle 是畫筆線型;POINT lopnWidth是按邏輯單位度量的畫筆寬度,只用其中的x值;COLORREF lopnColor是畫筆顏色

 

41 填充空隙

點式畫筆和虛線畫筆的空隙的着色取決於設備描述表的兩個屬性——背景模式和背景顏色。默認的背景模式是OPAQUE,在這種方式下,Windows使用背景色填充空隙,默認的背景色爲白色。

下述調用用來改變和獲取Windows用來填充空隙的背景色:

改變:SetBkColor(hdc, crColor);

獲取:GetBkColor(hdc);

 

下述調用用來改變和獲取背景模式:

改變:SetBkMode(hdc, 模式);

     模式:TRANSPARENT,忽略背景色,並且不填充空隙。

           OPAQUE默認。

獲取:GetBkMode(hdc);

 

42 繪圖方式

設備描述表中定義的繪圖方式也影響顯示器上所畫線的外觀。

當Windows使用畫筆來畫線時,實際上執行畫筆像素與目標位置處原來像素之間的某種按位布爾運算。像素間的按位布爾運算叫做“光柵運算”,簡稱爲“ROP”。由於畫一條直線只涉及兩種像素(畫筆和目標),因此這種布爾運算又稱爲“二元光柵運算”,簡稱爲“ROP2”。

在默認設備描述表中,繪圖方式定義爲R2_COPYPEN,這意味着Windows只是將畫筆像素複製到目標像素代替之。

Windows定義了16種不同的ROP2碼,用來設置不同的繪圖方式。

設置繪圖方式:SetROP2(hdc, iDrawMode);

獲取繪圖方式:iDrawMode = GetROP2(hdc);

 

43 繪製填充區域

Windows中有7個用來畫帶邊緣的填充圖形的函數:

① Rectangle:畫矩形

② Ellipse:畫橢圓

③ RoundRect:畫帶圓角的矩形

④ Pie:畫橢圓的一部分,使其看起來像一個扇形

⑤ Chord:畫橢圓的一部分,使其看起來像弓形

⑥ Polygon:畫多邊形

⑦ PolyPolygon:畫多個多邊形

 

Windows用設備描述表中選擇的當前畫筆來畫圖形的邊界框,邊界框還使用當前背景方式、背景色彩和繪圖方式,跟畫線時一樣。

圖形以當前設備描述表中選擇的刷子來填充。默認情況下,使用現有對象,這意味着圖形內部將畫成白色。

Windows定義6種現有刷子:WHITE_BRUSH、LTGRAY_BRUSH、GRAY_BRUSH、DKGRAY_BRUSH、BLACK_BRUSH和NULL_BRUSH。

也可以自己定義刷子 HBRUSH hBrush;

 

通過GetStockObject來獲取現有刷子:

hBrush = GetStockObject(WHITE_BRUSH);

通過SeletctObject將刷子選進設備描述表:

SelectObject(hdc, bBrush);

 

如果要畫一個沒有邊界框的圖形,可以將NULL_PEN選進設備描述表。

SelectObject(hdc, GetStockObject(NULL_PEN));

 

如果要畫一個沒有填充內部的圖像,可以將NULL_BRUSH選進設備描述表。

SelectObject(hdc, GetStockObject(NULL_BRUSH));

 

畫多邊形函數的原型:

Polygon(hdc, apt, iCount);

apt參數是POINT結構的一個數組,iCount是點的數目。如果該數組中的最後一個點和第一個點不同,則Windows將會再加一條線,將最後一個點與第一個點連起來。

 

畫多個多邊形函數的原型:

PolyPolygon(hdc, apt, aiCounts, iPolyCount);

apt數組具有全部多邊形的所有點。

aiCounts數組給出了多邊形的端點數。

iPolyCount給出了所畫的多邊形的個數。

 

44 用畫刷填充內部

Rectangle、RoundRect、Ellipse、Chord、Pie、Polygon和PolyPolygon圖形的內部是用選進設備描述表的當前畫刷來填充的。畫刷是一個8×8的位圖,它水平和垂直地重複使用來填充內部區域。

Windows有5個函數,可以自己創建邏輯畫刷,然後用SelectObject將畫刷選進設備描述表。

① hBrush = CreateSolidBrush(crColor); 純顏色刷子

② hBrush = CreateHatchBrush(iHatchStyle, crColor); 帶影射線的刷子

  crColor是影線的顏色,影線的間隙用設備描述表定義的背景方式和背景色來着色。

③ CreatePatternBrush()

④ CreateDIBPatternBrushPt() 基於位圖的刷子

⑤ hBrush = CreateBrushIndirect(&logbrush);

  該函數包含其他4個函數。

變量logbrush是一個類型爲LOGBRUSH的結構,該結構有三個字段

UINT lbStyle;

COLORREF lbColor;

LONG lbHatch;

 

45 矩形函數

Windows包含了幾種使用RECT結構和“區域”的繪圖函數。區域就是屏幕上的一塊地方,是矩形,多邊形和橢圓的組合。

FillRect(hdc, &rect, hBrush);

用指定畫刷來填充矩形。該函數不需要事先將畫刷選進設備描述表。

FrameRect(hdc, &rect, hBrush);

使用畫刷畫矩形框,但不填充矩形。

InvertRect(hdc, &rect);

將矩形中所有像素反轉。

 

常用矩形函數:

① SetRect(&rect, xLeft, yTop, xRight, yBottom); 設置矩形的4個字段值。

② OffsetRect(&rect, x, y); 將矩形沿x軸和y軸移動幾個單元。

③ InflateRect(&rect, x, y); 增減矩形尺寸

④ SetRectEmpty(&rect); 將矩形各字段設爲0

⑤ CopyRect(&DestRect, &SrcRect); 將矩形複製給另一個矩形。

⑥ IntersectRect(&DestRect, &SrcRect1,&ScrRect2);獲取兩個矩形的交集

⑦ UnionRect(&DestRect, &SrcRect1,&ScrRect2); 獲取兩個矩形的並集

⑧ bEmpty = IsRectEmpty(&rect); 確定矩形是否爲空

⑨ binRect = PtinRect(&rect, point);確定點是否在矩形內

 

46 創建和繪製區域

區域是對顯示器上一個範圍的描述,這個範圍是矩形、多邊形和橢圓的組合。

區域可以用於繪製和剪裁,通過將區域選進設備描述表,就可以用區域來進行剪裁。

當創建一個區域時,Windows返回一個該區域的句柄,類型爲HRGN。

HRGN hRgn;

① 創建矩形區域:

hRgn = CreateRectRgn(xLeft, yTop, xRight, yBottom);

hRgn = CreateRectRgnIndirect(&rect);

 

② 創建橢圓區域:

hRgn = CreateEllipticRgn(xLeft, yTop, xRight, yBottom);

hRgn = CreateEllipticRgnIndirect(&rect);

 

③ 創建多邊形區域:

hRgn = CreatePolygonRgn(&point, iCount, iPolyFillMode);

point參數是個POINT類型的結構數組;

iCount是點的數目;

iPolyFillMode是ALTERNATE或者WINDING

 

④ 區域的融合

iRgnType = CombineRgn(hDestRgn, hSrcRgn1, hSrcRgn2, iCombine);

這一函數將兩個源區域組合起來並用句柄hDestRgn指向組合成的目標區域。

iCombine參數說明了hSrcRgn1和hSrcRgn2是怎麼組合的。

RGN_AND  公共部分

RGN_OR    全部

RGN_XOR  全部除去公共部分

RGN_DIFF  hSrcRgn1不在hSrcRgn2的部分

RGN_COPY hSrcRgn1的全部,忽略hSrcRgn2

 

區域的句柄可以用到4個繪圖函數:

FillRgn(hdc, hRgn, hBrush);

FrameRgn(hdc, hRgn, xFrame, yFrame);

xFrame, yFrame是畫在區域周圍邊框的寬度和高度。

InvertRgn(hdc, hRgn);

PaintRgn(hdc, hRgn);

 

47 矩形與區域的剪裁

區域也在剪裁中扮演了一個角色。

InvalidateRect函數使顯示的一個矩形區域失效,併產生一個WM_PAINT消息。

InvalidateRect(hwnd, NULL, TRUE); 清除客戶區;

 

可以通過調用GetUpdateRect來獲取失效矩形的座標。

使用ValidateRect函數使客戶區的矩形有效。

當接收到一個WM_PAINT消息時,無效矩形的座標可以從PAINTSTRUCT結構中得到,該結構是用BeginPaint函數填充的。

Windows中有兩個作用於區域而不是矩形的函數:

InvalidateRgn(hwnd, hRgn, bErase);

ValidateRgn(hwnd, hRgn);

所以當接收到一個WM_PAINT消息時,可能由無效區域引起的。剪裁區域不一定是矩形。

 

SelectObject(hdc, hRgn);

SelectClipObject(hdc, hRgn);

通過將一個區域選進設備描述表來創建自己的剪裁區域。

 

 


 

 

轉自:http://blog.csdn.net/pizi0475/archive/2010/03/19/5395483.aspx


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