Windows消息機制
基本概念解釋
1) SDK和API
SDK: 軟件開發工具包(Software Development Kit),一般都是一些被軟件工程師用於為特定的軟件包、軟件框架、硬件平台、操作系統等建立應用軟件的開發工具的集合。
API函數: Windows操作系統提供給應用程序編程的接口(Application Programming Interface)。
Windows應用程序API函數是通過C語言實現的,所有主要的 Windows 函數都在 Windows.h 頭文件中進行了聲明。Windows 操作系統提供了 1000 多種 API函數。
2) 窗口和句柄
窗口是 Windows 應用程序中一個非常重要的元素,一個 Windows 應用程序至少要有一個窗口,稱為主窗口。
窗口是屏幕上的一塊矩形區域,是 Windows 應用程序與用戶進行交互的接口。利用窗口可以接收用戶的輸入、以及顯示輸出。
一個應用程序窗口通常都包含標題欄、菜單欄、系統菜單、最小化框、最大化框、 可調邊框,有的還有滾動條。如下圖:

窗口可以分為客戶區和非客戶區, 如上圖。 客戶區是窗口的一部分, 應用程序通常在客戶區中顯示文字或者繪制圖形。
標題欄、 菜單欄、 系統菜單、 最小化框和最大化框、 可調邊框統稱為窗口的非客戶區, 它們由 Windows 系統來管理, 而應用程序則主要管理客戶區的外觀及操作。
窗口可以有一個父窗口, 有父窗口的窗口稱為子窗口。除了上圖所示類型的窗口外, 對話框和消息框也是一種窗口。 在對話框上通常還包含許多子窗口, 這些子窗口的形式有按鈕、 單選按鈕、 復選框、 組框、 文本編輯框等。
在 Windows 應用程序中, 窗口是通過窗口句柄( HWND) 來標識的。 我們要對某個窗口進行操作, 首先就要得到這個窗口的句柄。
句柄( HANDLE) 是 Windows 程序中一個重要的概念, 使用也非常頻繁。 在 Windows 程序中, 有各種各樣的資源( 窗口、 圖標、光標,畫刷等), 系統在創建這些資源時會為它們分配內存, 並返回標識這些資源的標識號, 即句柄。
在后面的內容中我們還會看到圖標句柄( HICON)、 光標句柄( HCURSOR) 和畫刷句柄( HBRUSH)。
3) 消息與消息隊列
Windows 程序設計是一種完全不同於傳統的 DOS 方式的程序設計方法。它是一種事件驅動方式的程序設計模式,主要是基於消息的。
每一個 Windows 應用程序開始執行后, 系統都會為該程序創建一個消息隊列, 這個消息隊列用來存放該程序創建的窗口的消息。
例如,當用戶在窗口中畫圖的時候,按下鼠標左鍵,此時,操作系統會感知到這一事件,於是將這個事件包裝成一個消息,投遞到應用程序的消息隊列中,等待應用程序的處理。
然后應用程序通過一個消息循環不斷地從消息隊列中取出消息,並進行響應。
在這個處理過程中,操作系統也會給應用程序“ 發送消息”。所謂“ 發送消息”,實際上是操作系統調用程序中一個專門負責處理消息的函數,這個函數稱為窗口過程。

鼠標操作窗口時,操作系統先捕獲到消息,把消息放到消息隊列中,應用程序捕獲消息GetMessage(),然后DispatchMessage()分發消息給操作系統,操作系統調用回調函數----窗口過程
4) WinMain函數
當Windows操作系統啟動一個程序時,它調用的就是該程序的WinMain函數( 實際是由插入到可執行文件中的啟動代碼調用的)。
WinMain是Windows程序的入口點函數,與DOS程序的入口點函數main的作用相同,當WinMain 函數結束或返回時,Windows應用程序結束。
Windows 編程模型
一個完整的Win32程序(#include <windows.h>),該程序實現的功能是創建一個窗口,並在該窗口中響應鍵盤及鼠標消息,程序的實現步驟為:
1) WinMain函數的定義
2) 創建一個窗口
3) 進行消息循環
4) 編寫窗口過程函數
1) WinMain函數的定義
int WINAPI WinMain(
HINSTANCE hInstance, //應用程序實例
HINSTANCE hPrevInstance, //上一個應用程序實例
LPSTR lpCmdLine, //命令行參數
int nShowCmd); //窗口顯示的樣式
);
WINAPI:是一個宏,它代表的是__stdcall(注意是兩個下划線)
表示的是參數傳遞的順序:從右往左依次入棧,同時在函數返回前自動清空堆棧
hInstance:表示該程序當前運行的實例的句柄,這是一個數值。當程序在Windows下運行時,它唯一標識運行中的實例(注意,只有運行中的程序實例, 才有實例句柄)。一個應用程序可以運行多個實例,每運行一個實例,系統都會給該實例分配一個句柄值,並通過hInstance參數傳遞給 WinMain 函數。
hPrevInstance:表示當前實例的前一個實例的句柄。在Win32環境下,這個參數總是NULL,即在Win32環境下,這個參數不再起作用。
lpCmdLine:是一個以空終止的字符串, 指定傳遞給應用程序的命令行參數,相當於C或C++中的main函數中的參數char *argv[]。
nShowCmd:表示一個窗口的顯示,表示它是要最大化顯示、最小化顯示、正常大小顯示還是隱藏顯示。
2) 創建一個窗口
創建一個完整的窗口,需要經過下面幾個步驟:
1. 設計一個窗口類
一個完整的窗口具有許多特征, 包括光標(鼠標進入該窗口時的形狀)、圖標、背景色等。窗口的創建過程類似於汽車的制造過程。
我們在生產一個型號的汽車之前, 首先要對該型號的汽車進行設計, 在圖紙上畫出汽車的結構圖, 設計各個零部件, 同時還要給該型號的汽車取一個響亮的名字, 例如“寶馬 x6”。
類似地, 在創建一個窗口前, 也必須對該類型的窗口進行設計, 指定窗口的特征。
在Windows中,窗口的特征就是由WNDCLASS結構體來定義的,我們只需給WNDCLASS結構體對應的成員賦值,即可完成窗口類的設計。
WNDCLASS結構體的定義如下:
typedef struct _WNDCLASS{ UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCWSTR lpszMenuName; LPCWSTR lpszClassName; } WNDCLASS;
style:指定窗口的樣式(風格),常用的樣式如下:
| 類型 |
含義 |
| CS_HREDRAW |
當窗口水平方向上的寬度發生變化時, 將重新繪制整個窗口。 當窗口發生重繪時, 窗口中的文字和圖形將被擦除。如果沒有指定這一樣式,那么在水平方向上調整窗口寬度時,將不會重繪窗口。 |
| CS_VREDRAW |
當窗口垂直方向上的高度發生變化時,將重新繪制整個窗口。如果沒有指定這一樣式,那么在垂直方向上調整窗口高度時,將不會重繪窗口。 |
| CS_NOCLOSE |
禁用系統菜單的 Close 命令,這將導致窗口沒有關閉按鈕。 |
| CS_DBLCLKS |
當用戶在窗口中雙擊鼠標時,向窗口過程發送鼠標雙擊消息。 |
lpfnWndProc:指定一個窗口回調函數,是一個函數的指針。
當應用程序收到給某一窗口的消息時,就應該調用某一函數來處理這條消息。這一調用過程不用應用程序自己來實施,而由操作系統來完成,但是,回調函數本身的代碼必須由應用程序自己完成。
對於一條消息,操作系統調用的是接受消息的窗口所屬的類型中的lpfnWndProc成員指定的函數。每一種不同類型的窗口都有自己專用的回調函數,該函數就是通過lpfnWndProc成員指定的。
回調函數的定義形式如下:
LRESULT CALLBACK WindowProc( HWND hWnd, //信息所屬的窗口句柄 UINT uMsg, //消息類型 WPARAM wParam, //附加信息(如鍵盤哪個鍵按下) LPARAM lParam //附加信息(如鼠標點擊坐標) );
cbClsExtra:類的附加內存,通常數情況下為0。
cbWndExtra:窗口附加內存,通常情況下為0。
hInstance:當前實例句柄,用WinMain中的形參hInstance為其賦值。
hIcon:指定窗口類的圖標句柄,設置為NULL,則使用默認圖標,也可用如下函數進行賦值:
HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName); 如:LoadIcon(NULL, IDI_WARNING); //第一個參數為NULL,加載系統默認圖標
hCursor:指定窗口類的光標句柄,設置為NULL,則使用默認圖標,也可用如下函數進行賦值:
HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName); 如:LoadCursor(NULL, IDC_HELP); //第一個參數為NULL,加載系統默認光標
hbrBackground:指示窗口的背景顏色,可用如下函數進行賦值:
HGDIOBJ GetStockObject(int fnObject); 如:GetStockObject(WHITE_BRUSH);
lpszMenuName:指定菜單資源的名字。如果設置為NULL,那么基於這個窗口類創建的窗口將沒有默認菜單。
lpszClassName:指定窗口類的名字。
2. 注冊窗口類
設計完窗口類(WNDCLASS)后, 需要調用RegisterClass函數對其進行注冊,注冊成功后,才可以創建該類型的窗口。
注冊函數的原型聲明如下:
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
使用示例:RegisterClass(&wc);
3. 創建窗口
設計好窗口類並且將其成功注冊之后, 即可用CreateWindow函數產生這種類型的窗口了。
CreateWindow函數的原型聲明如下:
HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );
參數說明:
lpClassName:指定窗口類的名稱,此名字必須和WNDCLASS的lpszClassName成員指定的名稱一樣。
lpWindowName:指定窗口的名字,即窗口的標題。
dwStyle:指定創建的窗口的樣式,常指定為指WS_OVERLAPPEDWINDOW類型,這是一種多種窗口類型的組合類型。
x, y:指定窗口左上角的x,y坐標。如果參數x被設為CW_USEDEFAULT,那么系統為窗口選擇默認的左上角坐標並忽略y參數。
nWidth,nHeight:指定窗口窗口的寬度,高度。如果參數nWidth被設為 CW_USEDEFAULT,那么系統為窗口選擇默認的寬度和高度,參數nHeight被忽略。
hWndParent:指定被創建窗口的父窗口句柄,沒有父窗口,則設置NULL。
hMenu:指定窗口菜單的句柄,沒有,則設置為NULL。
hInstance:窗口所屬的應用程序實例的句柄,用WinMain中的形參hInstance為其賦值。
lpParam:作為WM_CREATE消息的附加參數lParam傳入的數據指針。通常設置為NULL。
返回值說明:如果窗口創建成功,CreateWindow函數將返回系統為該窗口分配的句柄,否則,返回NULL。
示例代碼:
HWND hWnd = CreateWindow( TEXT("MyWin"), //窗口類名字 TEXT("測試"), //窗口標題 WS_OVERLAPPEDWINDOW, //窗口風格 CW_USEDEFAULT, CW_USEDEFAULT, //窗口x,y坐標,使用默認值 CW_USEDEFAULT, CW_USEDEFAULT, //窗口寬度,高度,使用默認值 NULL, //無父窗口 NULL, //無菜單 hInstance, //應用程序實例句柄,為WinMain第1個形參 NULL); //附件信息,通常設置為NULL
4. 顯示及更新窗口
顯示窗口函數原型:
BOOL ShowWindow(HWND hWnd, int nCmdShow);
更新窗口函數原型:
BOOL UpdateWindow(HWND hWnd);
示例代碼:
ShowWindow(hWnd, SW_SHOWNORMAL); //SW_SHOWNORMAL為普通模式 UpdateWindow(hWnd);
5. 通過循環取消息
6. 處理消息(窗口過程)
在完成上述步驟后,剩下的工作就是編寫一個窗口過程函數,用於處理發送給窗口的消息。
窗口過程函數的名字可以隨便取, 如WinProc, 但函數定義的形式必須和下面聲明的形式相同:
//CALLBACK __stdcall 參數的傳遞順序,從右到左,依次入棧,並且在函數返回前清空堆棧 LRESULT CALLBACK WindowProc( HWND hwnd,//消息所屬的窗口句柄 UINT uMsg,//具體的消息名稱 WM__XXX消息名 WPARAM wParam,//鍵盤的附加消息 LPARAM lParam//鼠標的附加消息 )
DefWindowProc函數:DefWindowProc函數調用默認的窗口過程,對應用程序沒有處理的其他消息提供默認處理。
WM_CLOSE:對WM_CLOSE消息的響應並不是必須的,如果應用程序沒有對該消息進行響應,系統將把這條消息傳給DefWindowProc函數而 DefWindowProc函數則調用DestroyWindow函數來響應這條WM_CLOSE消息。
WM_DESTROY:DestroyWindow函數在銷毀窗口后,會給窗口過程發送 WM_DESTROY消息,我們在該消息的響應代碼中調用PostQuitMessage函數。
PostQuitMessage函數向應用程序的消息隊列中投遞一條WM_QUIT消息並返回。
WinMain函數中,GetMessage 函數只有在收到WM_QUIT消息時才返回0,此時消息循環才結束,程序退出。傳遞給 PostQuitMessage函數的參數值將作為WM_QUIT消息的wParam參數,這個值通常用做WinMain函數的返回值。
//處理窗口過程 //CALLBACK __stdcall 參數的傳遞順序,從右到左,依次入棧,並且在函數返回前清空堆棧 LRESULT CALLBACK WindowProc( HWND hwnd,//消息所屬的窗口句柄 UINT uMsg,//具體的消息名稱 WM__XXX消息名 WPARAM wParam,//鍵盤的附加消息 LPARAM lParam//鼠標的附加消息 ) { switch(uMsg) { case WM_CLOSE:
//所有xxxWindow為結尾的方法,都不會進入消息隊列中,而是直接執行 DestroyWindow(hwnd);//DestroyWindow發送另一個消息 WM_DESTROY break; case WM_DESTROY: PostQuitMessage(0); break; case WM_LBUTTONDOWN://鼠標左鍵按下 { int xPos=LOWORD(lParam); int yPos=HIWORD(lParam); char buf[1024]; wsprintf((LPWSTR)buf,TEXT("x=%d,y=%d"),xPos,yPos); MessageBox(hwnd,buf,TEXT("點擊"),MB_OK); break; } case WM_KEYDOWN://鍵盤 MessageBox(hwnd,TEXT("鍵盤按下"),TEXT("鍵盤按下"),MB_OK); break; case WM_PAINT://繪圖 { PAINTSTRUCT ps;//繪圖結構體 HDC hdc=BeginPaint(hwnd,&ps); TextOut(hdc,100,100,TEXT("hello world!"),strlen("hello world!")); EndPaint(hwnd,&ps); } break; } //返回值用默認處理方式 return DefWindowProc(hwnd,uMsg,wParam,lParam); }
#include<Windows.h>//底層實現窗口的頭文件 int WINAPI WinMain( HINSTANCE hInstance,//應用程序實例句柄 HINSTANCE hPrevInstance,//上一個應用程序句柄,在win32環境下,參數一般為NULL,不起作用了 LPSTR lpCmdLine, int nShowCmd ) { //1. 設計窗口 WNDCLASS wc; HWND hwnd; MSG msg; wc.cbClsExtra=0;//類的額外的內存 wc.cbWndExtra=0;//窗口的額外內存 wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);//設置背景 wc.hCursor=LoadCursor(NULL,IDC_HAND);//設置光標,如果第一個參數為NULL,代表使用系統提供的光標 wc.hIcon=LoadIcon(NULL,IDI_INFORMATION);//圖標 wc.hInstance=hInstance;//應用程序的實際句柄。傳入WinMain中的形參即可 //wc.lpfnWndProc=WindowProc;//回調函數,窗口過程 wc.lpszClassName=TEXT("WIN");//指定窗口類名稱 wc.lpszMenuName=NULL;//菜單名稱 wc.style=0;//顯示風格,0代表默認風格 //2. 注冊窗口類 RegisterClass(&wc); //3. 創建窗口 /* lpClassName:類名 lpWindowName:標題名 dwStyle:風格 x:顯示坐標 y:顯示坐標CW_USEDEFAULT默認值 nWidth:寬高 nHeight hWndParent:父窗口 hMenu:菜單NULL hInstance:實例句柄 lpParam :附加值,鼠標附加值 */ hwnd = CreateWindow(wc.lpszClassName, TEXT("WINDOWS"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); //4.顯示和更新 ShowWindow(hwnd,SW_SHOWNORMAL); UpdateWindow(hwnd); //5. 通過循環取消息 /* HWND hwnd;主窗口句柄 UINT message;具體的消息名稱 WPARAM wParam;附加消息,鍵盤消息 LPARAM lParam;附加消息,鼠標消息 DWORD time;消息產生的時間 POINT pt;附加消息,鼠標消息 x y */ while(1) { /* __out LPMSG lpMsg,消息 __in_opt HWND hWnd,捕獲窗口,填NULL代表捕獲所有的窗口 __in UINT wMsgFilterMin,最小和最大的過濾消息,一般填0 __in UINT wMsgFilterMax 填0代表捕獲所有消息 */ if(GetMessage(&msg,NULL,0,0)==FALSE) { break; } //翻譯消息 TranslateMessage(&msg); //不為false //分發消息 DispatchMessage(&msg); } return 0; }
注意:生成解決方案的時候出現“error C2275: “xxxxx”: 將此類型用作表達式非法”
錯誤是由於:c的編譯器要求將變量的聲明放在一個函數塊的頭部,而c++沒有這樣的要求造成的;解決的辦法就是把變量的聲明全部放在變量的生存塊的開始。
解決方法:將所有變量定義在代碼段的開頭
MFC入門
MFC是什么?
微軟基礎類庫(英語:Microsoft Foundation Classes,簡稱MFC)是一個微軟公司提供的類庫(class libraries),以C++類的形式封裝了Windows API,並且包含一個應用程序框架,以減少應用程序開發人員的工作量。其中包含的類包含大量Windows句柄封裝類和很多Windows的內建控件和組件的封裝類。
MFC把Windows SDK API函數包裝成了幾百個類,MFC給Windows操作系統提供了面向對象的接口,支持可重用性、自包含性以及其他OPP原則。MFC通過編寫類來封裝窗口、對話框以及其他對象,引入某些關鍵的虛函數(覆蓋這些虛函數可以改變派生類的功能)來完成,並且MFC設計者使類庫帶來的總開銷降到了最低。
編寫第一個MFC應用程序
1) 代碼的編寫
項目的創建和之前一樣,只是此次的源文件后綴為.cpp,因為MFC是由C++編寫的,編寫MFC程序需要包含#include <afxwin.h>頭文件

2) 程序執行流程
① 程序開始時,先實例化應用程序對象(有且只有一個)
② 執行程序的入口函數InitInstance()
③ 給框架類MyFrame對象動態分配空間(自動調用它的構造函數),在其構造函數內部,通過CWnd::Create創建窗口
④ 框架類對象顯示窗口CWnd::ShowWindow
⑤ 框架類對象更新窗口CWnd::UpdateWindow
⑥ 保存框架類對象指針CWinThread::m_pMainWnd
自定義類 繼承與CWinApp應用程序類 MyApp app 應用程序對象,有且僅有一個
#include "mfc.h" MyApp app;//全局應用程序對象,有且僅有一個 BOOL MyApp::InitInstance() { //創建窗口 MyFrame * frame=new MyFrame; //顯示和更新 frame->ShowWindow(SW_SHOWNORMAL); frame->UpdateWindow(); m_pMainWnd=frame;//保存指向應用程序的主窗口的指針 return TRUE;//返回正常初始化 } MyFrame::MyFrame() { Create(NULL,TEXT("mfc")); }
#include <afxwin.h> //mfc頭文件 class MyApp:public CWinApp///應用程序類 { public: //程序入口 virtual BOOL InitInstance(); }; class MyFrame:public CFrameWnd//窗口框架類 { public:MyFrame(); };
消息映射
消息映射是一個將消息和成員函數相互關聯的表
比如,框架窗口接收到一個鼠標左擊消息,MFC將搜索該窗口的消息映射,如果存在一個處理WM_LBUTTONDOWN消息的處理程序,然后就調用OnLButtonDown
下面是是將消息映射添加到一個類中所做的全部工作:
1) 所操作類中,聲明消息映射宏。
2) 通過放置標識消息的宏來執行消息映射,相應的類將在對BEGIN_MESSAGE_MAP和END_MESSAGE_MAP的調用之間處理消息。

3) 對應消息處理函數分別在類中聲明,類外定義:

聲明宏 寫到h中
分界宏 寫到.cpp中
找到消息宏,寫到分界宏之間
把函數原型聲明寫到.h 中
函數的實現寫到.cpp中
鼠標,鍵盤,繪圖
#include "mfc.h" MyApp app;//全局應用程序對象,有且僅有一個 BOOL MyApp::InitInstance() { //創建窗口 MyFrame * frame=new MyFrame; //顯示和更新 frame->ShowWindow(SW_SHOWNORMAL); frame->UpdateWindow(); m_pMainWnd=frame;//保存指向應用程序的主窗口的指針 return TRUE;//返回正常初始化 } //分界宏 BEGIN_MESSAGE_MAP(MyFrame,CFrameWnd) ON_WM_LBUTTONDOWN( )//鼠標左鍵按下 ON_WM_CHAR( )//鍵盤 END_MESSAGE_MAP() MyFrame::MyFrame() { Create(NULL,TEXT("mfc")); } void MyFrame::OnLButtonDown( UINT nFlags, CPoint point ) { /*TCHAR buf[1024]; wsprintf(buf,TEXT("x=%d,y=%d"),point.x,point.y); MessageBox(buf);*/ //mfc中的字符串 CString CString str; str.Format(TEXT("x=%d,,,,y=%d"),point.x,point.y); MessageBox(str); } void MyFrame::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ) { CString str; str.Format(TEXT("按下了%c 鍵"),nChar); MessageBox(str); }
#include <afxwin.h> //mfc頭文件 class MyApp:public CWinApp///應用程序類 { public: //程序入口 virtual BOOL InitInstance(); }; class MyFrame:public CFrameWnd//窗口框架類 { public:MyFrame(); //聲明宏 提供消息映射機制 DECLARE_MESSAGE_MAP() afx_msg void OnLButtonDown( UINT nFlags, CPoint point ); afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ); };
Windows字符集
1. 多字節 字符串 轉寬字節 L
2. 聲明 寬字節字符串 wchar_t
3. 統計寬字節字符串 wcslen
4. TEXT做了自適應編碼的轉換
5. char * CString 之間轉換
char*->CString
char * p3='ccc';
CString str=Cstring(p3);
CString->char *
CString tmp;
tmp=str;
char *pp=tmp.GetBuffer();
用向導生成一個MFC應用程序
MFC框架中一些重要的函數
1) InitInstance函數

應用程序類的一個虛函數,MFC應用程序的入口。
2) PreCreateWindow函數

當框架調用CreateEx函數創建窗口時,會首先調用PreCreateWindow函數。
通過修改傳遞給PreCreateWindow的結構體類型參數CREATESTRUCT,應用程序可以更改用於創建窗口的屬性。
在產生窗口之前讓程序員有機會修改窗口的外觀。
最后再調用CreateWindowEx函數完成窗口的創建。
3) OnCreate函數

OnCreate是一個消息響應函數,是響應WM_CREATE消息的一個函數,而WM_CREATE消息是由Create函數調用的。一個窗口創建(Create)之后,會向操作系統發送WM_CREATE消息,OnCreate()函數主要是用來響應此消息的。
onCreate與Create的區別:
1. Create()負責注冊並產生窗口,像動態創建控件中的Create()一樣,窗口創建之后會向操作系統發送WM_CREATE消息。
2. OnCreate()不產生窗口,只是在窗口顯示前設置窗口的屬性如風格、位置等。
3. OnCreate()是消息WM_CREATE的消息響應函數。
4) OnDraw和OnPaint

OnPaint是WM_PAINT消息的消息處理函數,在OnPaint中調用OnDraw,一般來說,用戶自己的繪圖代碼應放在OnDraw中。
1. OnPaint()是CWnd的類成員,負責響應WM_PAINT消息。
2. OnDraw()是CView的成員函數,沒有響應消息的功能。
當視圖變得無效時(包括大小的改變,移動,被遮蓋等等),Windows發送WM_PAINT消息。該視圖的OnPaint 處理函數通過創建CPaintDC類的DC對象來響應該消息並調用視圖的OnDraw成員函數。OnPaint最后也要調用OnDraw,因此一般在OnDraw函數中進行繪制。
通常我們不必編寫OnPaint處理函數。當在View類里添加了消息處理OnPaint()時,OnPaint()就會覆蓋掉OnDraw()。
如果有了OnDraw,不要再有OnPaint了,同時存在的話,OnPaint會把OnDraw覆蓋掉
