青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品


姚明,81年,97年開始接觸電腦,6年的編程學習經歷, 曾有4年工作經驗,最終轉向基礎理論學習和研究, 現華中理工科技大學在讀,有志于圖形學領域工作發展

EMAIL:alanvincentmail@gmail.com QQ:31547735

隨筆分類(34)

文章分類(99)

相冊

收藏夾(6)

編程技術網站

出國留學網站

數學資源網站

圖形學網站

英語資源網站

自由職業者

搜索

  •  

最新評論

 

跟我一起學圖形編程

                              作者:姚明           聯系方式:alanvincentmail@gmail.com     2011年1月22日 18:46:14

歡迎使用我的圖形學教程。我是計算機專業的學生,對圖形圖像技術有濃厚的興趣,就讀期間廣泛的涉及相關知識,但始終沒有深入研究。原因很簡單,我認為廣度可以決定深度,大學期間應博學,不宜專于細節。現在畢業了,我選擇了圖形學作為自己深入研究的方向。

關于圖形學,我也算是初學者,也許,與大家不同的是,在深入研究之前,我做了充分的知識準備,我計劃從點的繪制開始,實現一套完整的三維渲染流水線。朋友們,跟我一起學吧,讓我們披荊斬棘,一起攀上這座美麗的高峰!

下面,開始我們的第一步,創建一個windows下的窗口程序。

理論:

Windows 程序中,在寫圖形用戶界面時需要調用大量的標準 Windows Gui 函數。其實這對用戶和程序員來說都有好處,對于用戶,面對的是同一套標準的窗口,對這些窗口的操作都是一樣的,所以使用不同的應用程序時無須重新學習操作。對程序員來說,這些 Gui 源代碼都是經過了微軟的嚴格測試,隨時拿來就可以用的。當然至于具體地寫程序對于程序員來說還是有難度的。為了創建基于窗口的應用程序,必須嚴格遵守規范。作到這一點并不難,只要用模塊化或面向對象的編程方法即可。

下面我就列出在桌面顯示一個窗口的幾個步驟:

  1. 得到您應用程序的句柄(必需)
  2. 得到命令行參數(如果您想從命令行得到參數,可選)
  3. 注冊窗口類(必需,除非您使用 Windows 預定義的窗口類,如 MessageBox dialog box
  4. 產生窗口(必需)
  5. 在桌面顯示窗口(必需,除非您不想立即顯示它)
  6. 刷新窗口客戶區;
  7. 進入無限的獲取窗口消息的循環;
  8. 如果有消息到達,由負責該窗口的窗口回調函數處理;
  9. 如果用戶關閉窗口,進行退出處理。

相對于單用戶的 DOS 下的編程來說,Windows 下的程序框架結構是相當復雜的。但是 Windows DOS 在系統架構上是截然不同的。Windows 是一個多任務的操作系統,故系統中同時有多個應用程序彼此協同運行。這就要求 Windows 程序員必須嚴格遵守編程規范,并養成良好的編程風格。

Windows 中的文本是一個GUI(圖形用戶界面)對象。每一個字符實際上是由許多的像素點組成,這些點在有筆畫的地方顯示出來,這樣就會出現字符。這也是為什么我說繪制字符,而不是寫字符。通常您都是在您應用程序的客戶區繪制字符串(盡管您也可以在客戶區外繪制)。Windows 下的繪制字符串方法和 Dos 下的截然不同,在 Dos 下,您可以把屏幕想象成 85 x 25 的一個平面,而 Windows 下由于屏幕上同時有幾個應用程序的畫面,所以您必須嚴格遵從規范。Windows 通過把每一個應用程序限制在他的客戶區來做到這一點。當然客戶區的大小是可變的,您隨時可以調整。

在您在客戶區繪制字符串前,您必須從 Windows 那里得到您客戶區的大小,確實您無法像在 DOS 下那樣隨心所欲地在屏幕上任何地方繪制,繪制前您必須得到 Windows 的允許,然后 Windows 會告訴您客戶區的大小,字體,顏色和其它 GUI 對象的屬性。您可以用這些來在客戶區繪制

什么是設備環境DC)呢? 它其實是由 Windows 內部維護的一個數據結構。一個設備環境和一個特定的設備相連。像打印機和顯示器。對于顯示器來說,設備環境和一個個特定的窗口相連。

設備環境中的有些屬性和繪圖有關,像:顏色,字體等。您可以隨時改動那些缺省值,之所以保存缺省值是為了方便。您可以把設備環境想象成是Windows 為您準備的一個繪圖環境,而您可以隨時根據需要改變某些缺省屬性。

當應用程序需要繪制時,您必須得到一個設備環境的句柄。通常有幾種方法。

  • WM_PAINT 消息中使用 call BeginPaint
  • 在其他消息中使用 call GetDC
  • call CreateDC 建立你自己的 DC

您必須牢記的是,在處理單個消息后你必須釋放設備環境句柄。不要在一個消息處理中獲得設備環境句柄,而在另一個消息處理中在釋放它。

我們在Windows 發送 WM_PAINT 消息時處理繪制客戶區,Windows 不會保存客戶區的內容,它用的是方法是重繪機制(譬如當客戶區剛被另一個應用程序的客戶區覆蓋),Windows 會把 WM_PAINT 消息放入該應用程序的消息隊列。重繪窗口的客戶區是各個窗口自己的責任,您要做的是在窗口過程處理 WM_PAINT 的部分知道繪制什么和何如繪制。

您必須了解的另一個概念是無效區域Windows 把一個最小的需要重繪的正方形區域叫做無效區域。當 Windows 發現了一個無效區域后,它就會向該應用程序發送一個 WM_PAINT 消息,在 WM_PAINT 的處理過程中,窗口首先得到一個有關繪圖的結構體,里面包括無效區的坐標位置等。您可以通過調用BeginPaint 無效區有效,如果您不處理 WM_PAINT 消息,至少要調用缺省的窗口處理函數 DefWindowProc ,或者調用 ValidateRect 無效區有效。否則您的應用程序將會收到無窮無盡的 WM_PAINT 消息。

下面是響應該消息的步驟:

  1. 取得設備環境句柄
  2. 繪制客戶區
  3. 釋放設備環境句柄

注意,您無須顯式地讓無效區有效,這個動作由 BeginPaint 自動完成。您可以在 BeginPaint Endpaint 之間,調用所有的繪制函數。幾乎所有的GDI 函數都需要設備環境的句柄作為參數。

 

內容:

下面是我們簡單的窗口程序的源代碼。在進入復雜的細節前,我將提綱挈領地指出幾點要點:

  1. 您應當把程序中要用到的所有常量和結構體的聲明放到一個頭文件中,并且在源程序的開始處包含這個頭文件。這么做將會節省您大量的時間,也免得一次又一次的敲鍵盤。您也可以定義您自己的常量和結構體,但最好把它們放到獨立的頭文件中。
  2. 在其它地方運用頭文件中定義函數原型,常數和結構體時,要嚴格保持和頭文件中的定義一致,包括大小寫。在查詢函數定義時,這將節約您大量的時間;
  3. 如果想詳細系統的學習Windows編程,可以參考《windows程序設計》,點擊下載
  4. 如果你的系統中沒有安裝VC 或不會使用VC,我準備了精簡版本,只有10MB左右,無需復雜操作,也能編譯本教程中的代碼,生成程序,點擊下載
  5. 如果你對下面的代碼視如天書,那么請先看《譚浩強C語言教程》,務必熟讀,點擊下載

 

 1/*------------------------------------------------------------------------
 2  HELLOWIN.CPP -- Displays "你好, 歡迎使用YM的圖形學教程!" in client area 
 3                 (c) Charles Petzold, 1998 
 4-----------------------------------------------------------------------*/
 
 5#include <windows.h>
 6
 7LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 8 
 9int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
10                   PSTR szCmdLine, int iCmdShow)
11{
12static TCHAR szAppName[] = TEXT ("HelloWin") ;
13    HWND   hwnd ;
14    MSG    msg ;
15    WNDCLASS    wndclass ;
16    wndclass.style        = CS_HREDRAW | CS_VREDRAW ;
17    wndclass.lpfnWndProc  = WndProc ;
18    wndclass.cbClsExtra   = 0 ;
19    wndclass.cbWndExtra   = 0 ;
20    wndclass.hInstance    = hInstance ;
21    wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;
22    wndclass.hCursor      = LoadCursor (NULL, IDC_ARROW) ;
23    wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
24    wndclass.lpszMenuName = NULL ;
25    wndclass.lpszClassName= szAppName ;
26    RegisterClass (&wndclass);        
27    hwnd = CreateWindow( szAppName,      // window class name
28                   TEXT ("The Hello Program"),   // window caption
29                   WS_OVERLAPPEDWINDOW,  // window style
30                   CW_USEDEFAULT,// initial x position
31                   CW_USEDEFAULT,// initial y position
32                   CW_USEDEFAULT,// initial x size
33                   CW_USEDEFAULT,// initial y size
34                   NULL,         // parent window handle
35                   NULL,         // window menu handle
36                   hInstance,    // program instance handle
37                   NULL) ;      // creation parameters
38    ShowWindow (hwnd, iCmdShow) ;
39    UpdateWindow (hwnd) ;
40    while (GetMessage (&msg, NULL, 00))
41    {
42          TranslateMessage (&msg) ;
43          DispatchMessage (&msg) ;
44    }

45    return msg.wParam ;
46}

47LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
48{
49    HDC            hdc ;
50    PAINTSTRUCT     ps ;
51    RECT          rect ;
52    switch (message)
53    {
54    case   WM_PAINT:
55            hdc = BeginPaint (hwnd, &ps) ;
56            GetClientRect (hwnd, &rect) ;
57            DrawText (hdc, TEXT ("你好, 歡迎使用YM的圖形學教程! "), -1&rect,
58                   DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
59            EndPaint (hwnd, &ps) ;
60            return 0 ;
61    case   WM_DESTROY:
62            PostQuitMessage (0) ;
63            return 0 ;
64    }

65  return DefWindowProc (hwnd, message, wParam, lParam) ;
66}

67

 

 

分析:

看到一個簡單的 Windows 程序有這么多行,您是不是有點想撤? 但是您必須要知道的是上面的大多數代碼都是模板而已,模板的意思即是指這些代碼對差不多所有標準 Windows 程序來說都是相同的。在寫 Windows 程序時您可以把這些代碼拷來拷去,當然把這些重復的代碼寫到一個庫中也挺好。其實真正要寫的代碼集中在 WinMain 中。這和一些 C 編譯器一樣,無須要關心其它雜務,集中精力于 WinMain 函數。唯一不同的是 C 編譯器要求您的源代碼有必須有一個函數叫 WinMain。否則 C 無法知道將哪個函數和有關的前后代碼鏈接。相對C,匯編語言提供了較大的靈活性,它不強行要求一個叫 WinMain 的函數。

下面我們開始分析,您可得做好思想準備,這可不是一件太輕松的活。

HELLOWIN至少呼叫了18Windows函數。下面以它們在HELLOWIN中出現的次序列出這些函數以及各自的簡明描述:

  • LoadIcon 加載圖標供程序使用。
  • LoadCursor 加載鼠標光標供程序使用。
  • GetStockObject 取得一個圖形對象(在這個例子中,是取得繪制窗口背景的畫刷對象)。
  • RegisterClass 為程序窗口注冊窗口類別。
  • MessageBox 顯示消息框。
  • CreateWindow 根據窗口類別建立一個窗口。
  • ShowWindow 在屏幕上顯示窗口。
  • UpdateWindow 指示窗口自我更新。
  • GetMessage 從消息隊列中取得消息。
  • TranslateMessage 轉譯某些鍵盤消息。
  • DispatchMessage 將消息發送給窗口消息處理程序。
  • PlaySound 播放一個聲音文件。
  • BeginPaint 開始繪制窗口。
  • GetClientRect 取得窗口顯示區域的大小。
  • DrawText 顯示字符串。
  • EndPaint 結束繪制窗口。
  • PostQuitMessage 在消息隊列中插入一個「退出程序」消息。
  • DefWindowProc 執行內定的消息處理。

這些函數均在Platform SDK文件中說明,并在不同的表頭文件中聲明,其中絕大多數聲明在WINUSER.H中。

WinMain函數共有4個參數:應用程序的實例句柄,該應用程序的前一實例句柄,命令行參數串指針和窗口如何顯示。Win32 沒有前一實例句柄的概念,所以第二個參數總為0。之所以保留它是為了和 Win16 兼容的考慮,在 Win16下,如果 hPrevInst NULL,則該函數是第一次運行。特別注意:您不用必須申明一個名為 WinMain 函數,事實上在這方面您可以完全作主,您甚至無須有一個和 WinMain 等同的函數。您只要把 WinMain 中的代碼拷到GetCommandLine 之后,其所實現的功能完全相同。在 WinMain 返回時,產生一個返回值。然后在應用程序結束時通過 ExitProcess 函數把該返回碼傳遞給 Windows

 

 1    wndclass.style        = CS_HREDRAW | CS_VREDRAW ;
 2    wndclass.lpfnWndProc = WndProc ;
 3    wndclass.cbClsExtra   = 0 ;
 4    wndclass.cbWndExtra   = 0 ;
 5    wndclass.hInstance    = hInstance ;
 6    wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;
 7    wndclass.hCursor      = LoadCursor (NULL, IDC_ARROW) ;
 8    wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 9    wndclass.lpszMenuName = NULL ;
10   wndclass.lpszClassName= szAppName ;
11   RegisterClass (&wndclass); 
12

上面幾行從概念上說確實是非常地簡單。只要幾行指令就可以實現。其中的主要概念就是窗口類(window class),一個窗口類就是一個有關窗口的規范,這個規范定義了幾個主要的窗口的元素,如:圖標、光標、背景色、和負責處理該窗口的函數。您產生一個窗口時就必須要有這樣的一個窗口類。如果您要產生不止一個同種類型的窗口時,最好的方法就是把這個窗口類存儲起來,這種方法可以節約許多的內存空間。也許今天您不會太感覺到,可是想想以前 PC 大多數只有 1M 內存時,這么做是非常有必要的。如果您要定義自己的創建窗口類就必須:在一個 WINDCLASS WINDOWCLASSEX 結構體中指明您窗口的組成元素,然后調用 RegisterClass RegisterClass ,再根據該窗口類產生窗口。對不同特色的窗口必須定義不同的窗口類。 WINDOWS有幾個預定義的窗口類,譬如:按鈕、編輯框等。要產生該種風格的窗口無須預先再定義窗口類了,只要包預定義類的類名作為參數調用 CreateWindow 即可。

WNDCLASS 中最重要的成員莫過于lpfnWndProc了。前綴 lpfn 表示該成員是一個指向函數的長指針。在 Win32中由于內存模式是 FLAT 型,所以沒有 near far 的區別。每一個窗口類必須有一個窗口過程,當 Windows 把屬于特定窗口的消息發送給該窗口時,該窗口的窗口類負責處理所有的消息,如鍵盤消息或鼠標消息。由于窗口過程差不多智能地處理了所有的窗口消息循環,所以您只要在其中加入消息處理過程即可。下面我將要講解 WNDCLASSEX 的每一個成員

 1typedef struct tagWNDCLASS {
 2  UINT      style;
 3  WNDPROC   lpfnWndProc;
 4  int       cbClsExtra;
 5  int       cbWndExtra;
 6  HINSTANCE hInstance;
 7  HICON     hIcon;
 8  HCURSOR   hCursor;
 9  HBRUSH    hbrBackground;
10  LPCTSTR   lpszMenuName;
11  LPCTSTR   lpszClassName;
12}
 WNDCLASS, *PWNDCLASS;
13
14CreateWindow( szAppName,      // window class name
15                   TEXT ("The Hello Program"),   // window caption
16                   WS_OVERLAPPEDWINDOW,  // window style
17                   CW_USEDEFAULT,// initial x position
18                   CW_USEDEFAULT,// initial y position
19                   CW_USEDEFAULT,// initial x size
20                   CW_USEDEFAULT,// initial y size
21                   NULL,         // parent window handle
22                   NULL,         // window menu handle
23                   hInstance,    // program instance handle
24                   NULL) ;      // creation parameters
25

注冊窗口類后,我們將調用CreateWindow來產生實際的窗口。請注意該函數有11個參數。

 

 1HWND WINAPI CreateWindow(
 2  __in_opt  LPCTSTR lpClassName,
 3  __in_opt  LPCTSTR lpWindowName,
 4  __in      DWORD dwStyle,
 5  __in      int x,
 6  __in      int y,
 7  __in      int nWidth,
 8  __in      int nHeight,
 9  __in_opt  HWND hWndParent,
10  __in_opt  HMENU hMenu,
11  __in_opt  HINSTANCE hInstance,
12  __in_opt  LPVOID lpParam
13);
14

 

我們來仔細看一看這些的參數:

  • lpClassName:(必須)。ASCIIZ形式的窗口類名稱的地址。可以是您自定義的類,也可以是預定義的類名。像上面所說,每一個應用程序必須有一個窗口類。
  • lpWindowNameASCIIZ形式的窗口名稱的地址。該名稱會顯示在標題條上。如果該參數空白,則標題條上什么都沒有。
  • dwStyle:窗口的風格。在此您可以指定窗口的外觀。可以指定該參數為零,但那樣該窗口就沒有系統菜單,也沒有最大化和最小化按鈕,也沒有關閉按鈕,那樣您不得不按Alt+F4 來關閉它。最為普遍的窗口類風格是 WS_OVERLAPPEDWINDOW。 一種窗口風格是一種按位的掩碼,這樣您可以用“or”把您希望的窗口風格或起來。像 WS_OVERLAPPEDWINDOW 就是由幾種最為不便普遍的風格或起來的。
  • XY: 指定窗口左上角的以像素為單位的屏幕坐標位置。缺省地可指定為 CW_USEDEFAULT,這樣 Windows 會自動為窗口指定最合適的位置。
  • nWidth nHeight: 以像素為單位的窗口大小。缺省地可指定為 CW_USEDEFAULT,這樣 Windows 會自動為窗口指定最合適的大小。
  • hWndParent: 父窗口的句柄(如果有的話)。這個參數告訴 Windows 這是一個子窗口和他的父窗口是誰。這和 MDI(多文檔結構)不同,此處的子窗口并不會局限在父窗口的客戶區內。他只是用來告訴 Windows 各個窗口之間的父子關系,以便在父窗口銷毀是一同把其子窗口銷毀。在我們的例子程序中因為只有一個窗口,故把該參數設為 NULL
  • hMenu WINDOWS菜單的句柄。如果只用系統菜單則指定該參數為NULL。回頭看一看WNDCLASSEX 結構中的 lpszMenuName 參數,它也指定一個菜單,這是一個缺省菜單,任何從該窗口類派生的窗口若想用其他的菜單需在該參數中重新指定。其實該參數有雙重意義:一方面若這是一個自定義窗口時該參數代表菜單句柄,另一方面,若這是一個預定義窗口時,該參數代表是該窗口的 ID 號。Windows 是根據lpClassName 參數來區分是自定義窗口還是預定義窗口的。
  • hInstance: 產生該窗口的應用程序的實例句柄。
  • lpParam: (可選)指向欲傳給窗口的結構體數據類型參數的指針。如在MDI中在產生窗口時傳遞 CLIENTCREATESTRUCT 結構的參數。一般情況下,該值總為零,這表示沒有參數傳遞給窗口。可以通過GetWindowLong 函數檢索該值。
 
1ShowWindow (hwnd, iCmdShow) ;
2UpdateWindow (hwnd) ;
調用CreateWindow成功后,會返回窗口句柄。我們必須保存該值以備后用。我們剛剛產生的窗口不會自動顯示,所以必須調用 ShowWindow 來按照我們希望的方式來顯示該窗口。接下來調用 UpdateWindow 來更新客戶區。 

 

1while (GetMessage (&msg, NULL, 00))
2{
3     TranslateMessage (&msg) ;
4     DispatchMessage (&msg) ;
5}


這時候我們的窗口已顯示在屏幕上了。但是它還不能從外界接收消息。所以我們必須給它提供相關的消息。我們是通過一個消息循環來完成該項工作的。每一個模塊僅有一個消息循環,我們不斷地調用 GetMessage Windows 中獲得消息。GetMessage 傳遞一個 MSG 結構體給 Windows ,然后 Windows 在該函數中填充有關的消息,一直到 Windows 找到并填充好消息后 GetMessage 才會返回。在這段時間內系統控制權可能會轉移給其他的應用程序。這樣就構成了Win16 下的多任務結構。如果 GetMessage 接收到 WM_QUIT 消息后就會返回 FALSE,使循環結束并退出應用程序。TranslateMessage 函數是一個是實用函數,它從鍵盤接受原始按鍵消息,然后解釋成 WM_CHAR,在把 WM_CHAR 放入消息隊列,由于經過解釋后的消息中含有按鍵的 ASCII 碼,這比原始的掃描碼好理解得多。如果您的應用程序不處理按鍵消息的話,可以不調用該函數。DispatchMessage 會把消息發送給負責該窗口過程的函數。

1return msg.wParam


如果消息循環結束了,退出碼存放在 MSG 中的 wParam中,您可以通過把它放到 eax 寄存器中傳給 Windows目前 Windows 沒有利用到這個結束碼,但我們最好還是遵從 Windows 規范已防意外。

 

1LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);


是我們的窗口處理函數。您可以隨便給該函數命名。其中第一個參數 hWnd 是接收消息的窗口的句柄。message是接收的消息。注意message不是一個 MSG 結構,其實上只是一個 DWORD 類型數。Windows 定義了成百上千個消息,大多數您的應用程序不會處理到。當有該窗口的消息發生時,Windows 會發送一個相關消息給該窗口。其窗口過程處理函數會智能的處理這些消息。wParam lParam 只是附加參數,以方便傳遞更多的和該消息有關的數據。

 1switch (message)
 2{
 3    case   WM_PAINT:
 4            hdc = BeginPaint (hwnd, &ps) ;
 5            GetClientRect (hwnd, &rect) ;
 6            DrawText (hdc, TEXT ("你好, 歡迎使用YM的圖形學教程!"), -1&rect,
 7                   DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
 8            EndPaint (hwnd, &ps) ;
 9            return 0 ;
10    case   WM_DESTROY:
11            PostQuitMessage (0) ;
12            return 0 ;
13}

14    return DefWindowProc (hwnd, message, wParam, lParam) ;
15


上面可以說是關鍵部分。這也是我們寫 Windows 程序時需要改寫的主要部分。此處您的程序檢查 Windows 傳遞過來的消息,如果是我們感興趣的消息則加以處理,處理完后,在 eax 寄存器中傳遞 0,否則必須調用 DefWindowProc,把該窗口過程接收到的參數傳遞給缺省的窗口處理函數。所有消息中您必須處理的是 WM_DESTROY,當您的應用程序結束時 Windows 把這個消息傳遞進來,當您的應用程序解說到該消息時它已經在屏幕上消失了,這僅是通知您的應用程序窗口已銷毀,您必須自己準備返回 Windows 。在此消息中您可以做一些清理工作,但無法阻止退出應用程序。如果您要那樣做的話,可以處理 WM_CLOSE 消息。在處理完清理工作后,您必須調用 PostQuitMessage,該函數會把 WM_QUIT 消息傳回您的應用程序,而該消息會使得 GetMessage 返回,并在將返回值設置0,然后會結束消息循環并退回 WINDOWS。您可以在您的程序中調用 DestroyWindow 函數,它會發送一個 WM_DESTROY 消息給您自己的應用程序,從而迫使它退出。

特別注意:下面討論的是我們以后的課程的核心部分

1 HDC            hdc ;
2 PAINTSTRUCT     ps ;
3 RECT          rect ;
4


這些局部變量由處理 WM_PAINT 消息中的 GDI 函數調用。hdc 用來存放調用 BeginPaint 返回的設備環境句柄。ps 是一個 PAINTSTRUCT 數據類型的變量。通常您不會用到其中的許多值,它由 Windows 傳遞給 BeginPaint,在結束繪制后再原封不動的傳遞給 EndPaintrect 是一個 RECT 結構體類型參數,它的定義如下:

1typedef struct _RECT {
2  LONG left;
3  LONG top;
4  LONG right;
5  LONG bottom;
6}
 RECT, *PRECT;
7


 left top 是正方形左上角的坐標。right bottom 是正方形右下角的坐標。客戶區的左上角的坐標是 x=0y=0,這樣對于 x=0y=10 的坐標點就在它的下面。

1      hdc = BeginPaint (hwnd, &ps) ;
2      GetClientRect (hwnd, &rect) ;
3      DrawText (hdc, TEXT ("你好, 歡迎使用YM的圖形學教程!"), -1&rect,
4                   DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
5       EndPaint (hwnd, &ps) ;
6


在處理 WM_PAINT 消息時,您調用BeginPaint函數,傳給它一個窗口句柄和未初始化的 PAINTSTRUCT 型參數。調用成功后在 eax 中返回設備環境的句柄。下一次,調用 GetClientRect 以得到客戶區的大小,大小放在 rect 中,然后把它傳給 DrawTextDrawText 的語法如下:

1int DrawText(
2  HDC hDC, 
3  LPCTSTR lpString, 
4  int nCount, 
5  LPRECT lpRect, 
6  UNIT uFormat);
7


 DrawText是一個高層的調用函數。它能自動處理像換行、把文本放到客戶區中間等這些雜事。所以您只管集中精力繪制字符串就可以了。我們會在下一課中講解低一層的函數 TextOut,該函數在一個正方形區域中格式化一個文本串。它用當前選擇的字體、顏色和背景色。它處理換行以適應正方形區域。它會返回以設備邏輯單位度量的文本的高度,我們這里的度量單位是像素點。讓我們來看一看該函數的參數:

  • hdc設備環境的句柄。
  • lpString:要顯示的文本串,該文本串要么以NULL結尾,要么在nCount中指出它的長短。
  • nCount:要輸出的文本的長度。若以NULL結尾,該參數必須是-1
  • lpRect: 指向要輸出文本串的正方形區域的指針,該方形必須是一個裁剪區,也就是說超過該區域的字符將不能顯示。
  • uFormat:指定如何顯示。我們可以用 or 把以下標志或到一塊:
    • DT_SINGLELINE:是否單行顯示。
    • DT_CENTER:是否水平居中。
    • DT_VCENTER :是否垂直居中。

 

結束繪制后,必須調用 EndPaint 釋放設備環境的句柄。好了,現在我們把繪制文本串的要點總結如下:

  1. 必須在開始和結束處分別調用 BeginPaint EndPaint
  2. BeginPaint EndPaint 之間調用所有的繪制函數;
  3. 如果在其它的消息處理中重新繪制客戶區,您可以有兩種選擇:
    1)用GetDCReleaseDC代替BeginPaintEndPaint
    2)調用InvalidateRectUpdateWindow讓客戶區無效,這將迫使WINDOWSWM_PAINT放入應用程序消息隊列,從而使得客戶區重繪。

 

posted on 2011-01-22 14:49 姚明 閱讀(1209) 評論(0)  編輯 收藏 引用 所屬分類: 原創教程
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久狠狠亚洲综合| 亚洲一区欧美二区| 香蕉尹人综合在线观看| 亚洲高清视频一区| 在线播放不卡| 久久视频这里只有精品| 欧美日韩专区| 欧美日韩性生活视频| 免费欧美电影| 欧美成人精品福利| 欧美激情久久久久久| 欧美区一区二| 欧美视频在线看| 国产精品视频免费在线观看| 国产欧美日韩免费| 在线观看日韩av电影| 亚洲精品日韩在线| 一本色道久久综合亚洲精品按摩| 新狼窝色av性久久久久久| 久久网站热最新地址| 亚洲免费观看| 久久精品在线免费观看| 欧美人与禽猛交乱配| 国产欧美亚洲视频| 亚洲免费电影在线| 久久久久九九视频| 亚洲毛片av| 久久久久久综合网天天| 欧美三级韩国三级日本三斤| 好看的日韩视频| 这里只有精品电影| 久久亚洲精品欧美| 亚洲视频在线看| 农村妇女精品| 国内偷自视频区视频综合| 亚洲网友自拍| 亚洲国产精品欧美一二99| 夜夜精品视频一区二区| 欧美1区视频| 18成人免费观看视频| 午夜久久久久| 欧美精品一区二区在线播放| 影视先锋久久| 小嫩嫩精品导航| 亚洲精品美女久久久久| 久久激情婷婷| 国产精品视频一区二区三区| 一本一道久久综合狠狠老精东影业 | 亚洲欧美电影在线观看| 久久男人资源视频| 国产亚洲一区精品| 亚洲欧美在线免费| 日韩午夜三级在线| 欧美成人午夜| 亚洲国产精品成人| 亚洲片区在线| 先锋影音久久久| 免费看亚洲片| 久久久久www| 久久人人爽国产| 日韩视频不卡| 羞羞视频在线观看欧美| 亚洲免费视频一区二区| 国产精品成人免费视频 | 亚洲一区二区在线观看视频| 久久久久久久久久久久久女国产乱 | 一区二区三区精品国产| 亚洲欧美日韩另类| 免费成人美女女| 欧美精品97| 国产精品永久免费在线| 欧美国产日韩a欧美在线观看| 亚洲经典视频在线观看| 亚洲精品自在久久| 亚洲一区在线视频| 欧美另类专区| 欧美黑人国产人伦爽爽爽| 国产精品国产三级国产普通话99| 国产精品wwwwww| 亚洲美女在线视频| 麻豆久久精品| 99热免费精品| 欲色影视综合吧| 亚洲国产成人久久| 亚洲一区二区三区在线观看视频| 久久久亚洲影院你懂的| 美女啪啪无遮挡免费久久网站| 亚洲一二三级电影| 国产精品国产三级国产| 日韩亚洲欧美中文三级| 亚洲综合丁香| 久久免费99精品久久久久久| 亚洲一区二区免费看| 国产精品爱久久久久久久| 在线免费一区三区| 亚洲一区日韩在线| 国产美女一区二区| 亚洲人成精品久久久久| 免费精品视频| 亚洲激情校园春色| 欧美影视一区| 国产麻豆9l精品三级站| 亚洲图片欧美日产| 亚洲精品一二| 久久国产精品久久国产精品| 亚洲一区二区三区四区视频| 亚洲日本无吗高清不卡| 国产精品一区二区三区乱码| 久久精品国产久精国产思思| 亚洲第一在线| 久久久久久电影| 国产伦理精品不卡| 欧美一级日韩一级| 在线亚洲观看| 亚洲国产精品热久久| 亚洲欧美精品suv| 9久草视频在线视频精品| 欧美在线日韩在线| 亚洲一卡久久| 欧美搞黄网站| 玖玖综合伊人| 国产亚洲精品久久久| 国产午夜精品麻豆| 鲁鲁狠狠狠7777一区二区| 在线性视频日韩欧美| 国产欧美一区二区精品仙草咪| 亚洲婷婷在线| 久久精品导航| 国内精品久久久久久久影视蜜臀 | 你懂的视频欧美| 国产精品v欧美精品∨日韩| 久久性色av| 国产精品三上| 亚洲影院高清在线| 亚洲欧美日韩综合aⅴ视频| 欧美色网一区二区| 国产精品v片在线观看不卡| 欧美成人首页| 亚洲高清三级视频| 免费观看日韩av| 欧美激情日韩| 一区二区电影免费在线观看| 欧美巨乳在线观看| 日韩视频―中文字幕| 中文国产一区| 国产精品欧美久久| 校园春色综合网| 久久久噜噜噜久噜久久| 黄色精品在线看| 久久嫩草精品久久久久| 欧美激情一区二区三区| 一区二区三区日韩精品视频| 欧美视频日韩视频| 午夜精品久久久久久| 久热精品在线视频| 99国产精品99久久久久久粉嫩| 欧美日韩亚洲天堂| 亚洲男同1069视频| 欧美成人中文字幕在线| 一区二区三区.www| 国产亚洲福利一区| 噜噜噜噜噜久久久久久91| 一区二区三区蜜桃网| 久久亚洲欧美| 在线午夜精品自拍| 老鸭窝91久久精品色噜噜导演| 免费观看亚洲视频大全| 日韩西西人体444www| 欧美午夜精品久久久久久人妖| 欧美一区二区在线| 99re6这里只有精品| 久久天堂成人| 亚洲一区二区三区中文字幕| 黄色欧美日韩| 国产精品捆绑调教| 欧美成年人视频网站| 亚洲一区二区成人在线观看| 美女视频网站黄色亚洲| 亚洲网站在线| 亚洲国产精品va在线看黑人| 99爱精品视频| 欧美国产欧美亚州国产日韩mv天天看完整| 国产精品99免费看 | av成人免费| 久久精品在线免费观看| 一本久久精品一区二区| 一区二区三区在线视频免费观看| 欧美日韩国产不卡在线看| 久久精品亚洲一区二区| 亚洲视频二区| 亚洲精品乱码久久久久久日本蜜臀 | 久久国产天堂福利天堂| 99国产麻豆精品| 国产综合久久| 国产麻豆精品theporn| 欧美四级剧情无删版影片| 欧美国产视频一区二区| 久久网站热最新地址| 久久精品国产一区二区三区| 亚洲在线不卡|