MFC創建應用程序啓示錄(創世紀新篇)

MFC是vc+的核心部分,須要必定的編程功底。 程序員

 Windows編程基礎
編制一個功能強大和易操做的Windows應用程序所須要的代碼確定會比通常的C++程序要多得多,但並非全部的代碼都須要本身從頭開始編寫,由於Visual C++不只提供了經常使用的Windows應用程序的基本框架,並且能夠在框架程序中直接調用Win32 API(Application Programming
Interface, 應用程序接口)函數。這樣,用戶僅須要在相應的框架位置中添加本身的代碼或修改部分代碼就可實現Windows應用程序的許多功能。 數據庫

簡單的Windows應用程序
 
先來看一個最簡單的Windows應用程序Ex_HelloMsg。
[例Ex_HelloMsg] 一個簡單的Windows應用程序
#include <windows.h>
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow)
{
     MessageBox (NULL, "你好,個人Visual C++世界!", "問候", 0) ;
     return 0 ;
}
在Visual C++ 6.0運行上述程序須要進行如下步驟:
(1) 選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在「工程」標籤頁面的列表框
中,選中Win32 Application項。
(2) 在工程編輯框中鍵入Win32應用程序項目名稱Ex_HelloMsg。在「位置」編輯框中直
接鍵入文件夾名稱,或單擊瀏覽按鈕選擇一個已有的文件夾。
(3) 單擊[肯定]按鈕繼續。一個詢問項目類型的Win32應用程序嚮導將被顯示,選中An
empty project項。單擊[完成]按鈕,系統將顯示該應用程序嚮導的建立信息,單擊[確
定]按鈕系統將自動建立此應用程序。
(4) 再次選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在「文件」標籤頁面左邊的
列表框中選擇C++ Source File項,在右邊的文件框中鍵入Ex_HelloMsg.cpp,單擊
[肯定]按鈕。 編程

 
[例Ex_HelloMsg] 一個簡單的Windows應用程序
(5) 輸入上面的代碼,運行程序,結果如圖3.1所示。
從上面的程序能夠看出:
● C++控制檯應用程序以main函數做爲進入程序的初始入口點,但在Windows應用程
序中,main主函數被WinMain函數取代。WinMain函數的原型以下:
int WINAPI WinMain (
HINSTANCE hInstance, // 當前實例句柄
HINSTANCE hPrevInstance, // 前一實例句柄
LPSTR lpCmdLine, // 指向命令行參數的指針
int nCmdShow) // 窗口的顯示狀態 windows

 
所謂句柄是一個標識Windows資源(如菜單、圖標、窗口等)和設備等對象的數據指針類型。一般,一個句柄變量可用來對系統中某些資源的間接引用。
●每個C++ Windows應用程序都須要Windows.h頭文件,它還包含了其餘的一些Windows頭文件。這些頭文件定義了Windows的全部數據類型、函數調用、數據結構和符號常量。
●程序中,MessageBox是一個Win32 API函數,用來彈出一個消息對話框。該函數第一個參數用來指定父窗口句柄,即對話框所在的窗口句柄。第2、三個參數分別用來指定顯示的消息內容和對話框窗口的標題,最後一個參數用來指定在對話框中顯示的按鈕。 瀏覽器

 
[例Ex_HelloWin] 一個完整的Windows應用程序
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); // 窗口過程
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow)
{
     HWND       hwnd ; // 窗口句柄
     MSG        msg ; // 消息
     WNDCLASS wndclass ; // 窗口類
     wndclass.style  = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = "HelloWin"; // 窗口類名
     if (!RegisterClass (&wndclass)) 
 
{ // 註冊窗口
          MessageBox (NULL, "窗口註冊失敗!", "HelloWin", 0) ;    
          return 0 ;
}
 hwnd = CreateWindow ("HelloWin",                 // 窗口類名
                          "個人窗口", // 窗口標題
                          WS_OVERLAPPEDWINDOW,    // 窗口樣式
                          CW_USEDEFAULT,              // 窗口最初的 x 位置
                          CW_USEDEFAULT,              // 窗口最初的 y 位置
                          CW_USEDEFAULT,              // 窗口最初的 x 大小
                          CW_USEDEFAULT,              // 窗口最初的 y 大小
                          NULL,                       // 父窗口句柄
                          NULL,                       // 窗口菜單句柄
                          hInstance,                  // 應用程序實例句柄
                          NULL) ;                     // 建立窗口的參數
     ShowWindow (hwnd, nCmdShow) ; // 顯示窗口
     UpdateWindow (hwnd) ; // 更新窗口,包括窗口的客戶區
     // 進入消息循環:當從應用程序消息隊列中檢取的消息是WM_QUIT時,則退出循環。
     while (GetMessage (&msg, NULL, 0, 0))
    {
TranslateMessage (&msg) ; // 轉換某些鍵盤消息
         DispatchMessage (&msg) ; // 將消息發送給窗口過程,這裏是WndProc
     } 
 
}
     return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
     switch (message)
     {
case WM_CREATE:   // 窗口建立產生的消息
return 0 ;         
case WM_LBUTTONDOWN:
MessageBox (NULL, "你好,個人Visual C++世界!", "問候", 0) ;
  return 0 ;         
case WM_DESTROY: // 當窗口關閉時產生的消息
  PostQuitMessage (0) ;
  return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;    // 執行默認的消息處理
} 數據結構

 
程序運行後,單擊鼠標左鍵,就會彈出一個對話框,結果如圖3.2所示 框架

 
窗口過程函數WndProc用來接收和處理各類不一樣的消息,而主函數WinMain一般要完成如下幾步工做:
(1) 調用API函數RegisterClass註冊應用程序的窗口類。
(2) 調用相關API函數建立和顯示窗口,並進行其它必要的初始化處理。其中,函數CreateWindow用來建立已註冊窗口類的窗口。Windows每個窗口都有一些基本屬性,如窗口標題、窗口位置和大小、應用程序圖標、鼠標指針、菜單和背景顏色等。窗口類就是充當這些屬性的模板。
(3) 建立和啓動應用程序的消息循環。Windows應用程序接受各類不一樣的消息,包括鍵盤消息、鼠標以及窗口產生的各類消息。Windows系統首先將消息放入消息隊列中,應用程序的消息循環就是從應用程序的消息隊列中檢取消息,並將消息發送相應的窗口過程函數中做進一步處理。API函數GetMessage 和DispatchMessage就是起到這樣的做用。
(4) 若是接收到WM_QUIT消息,則退出應用程序。 編輯器

 
圖3.3  Windows應用程序的基本流程  函數

 Windows編程特色

一個完整的Windows應用程序除了WinMain函數外,還包含用於處理用戶動做和
窗口消息的窗口函數。這不一樣於一個C++的控制檯應用程序,能夠將整個程序包
含在main函數中。事實上,它們的區別還遠不止這些,不久還會發現一個
Windows應用程序還經常具備這樣的一些特性:
● 消息驅動機制
●圖形設備接口(GDI)
●基於資源的程序設計
●動態連接庫
●進程和線程 工具

 

 
1. 消息驅動機制
在Windows操做環境中,不管是系統產生的動做或是用戶運行應用程序產生的動
做,都稱爲事件(Events)產生的消息(Message)。例如,在Windows 桌面(傳統風
格)上,雙擊應用程序的快捷圖標,系統就會執行該應用程序。在Windows的應
用程序中,也是經過接收消息、分發消息、處理消息來和用戶進行交互的。
這種消息驅動的機制是Windows編程的最大特色。須要注意的是,許多Windows
消息都通過了嚴格的定義,而且適用於全部的應用程序。例如,當用戶按下鼠標
的左鍵時系統就會發送WM_LBUTTONDOWN消息,而當用戶敲了一個字符鍵時
系統就會發送WM_CHAR消息,若用戶進行菜單選擇或工具按鈕單擊等操做時,
系統又會相應地發送WM_COMMAND消息給相應的窗口等等。

 
2. 圖形設備接口(GDI)
在傳統的DOS環境中,想要在打印機上打印一幅圖形是一件很是複雜的事情,因
爲用戶必須根據打印機類型和指令規則向打印機輸送數據。而Windows則提供了
一個抽象的接口,稱爲圖形設備接口(Graphical Device Interface,簡稱GDI),
使得用戶直接利用系統的GDI函數就能方便實現輸入或輸出,而沒必要關心與系統
相連的外部設備的類型。
3. 基於資源的程序設計
Windows應用程序經常包含衆多圖形元素,例如光標、菜單、工具欄、位圖、對
話框等,在Windows環境下,每個這樣的元素都做爲一種能夠裝入應用程序的
資源來存放。這些資源就像C++程序中的常量同樣,能夠被編輯、修改,也能夠
被其餘應用程序所共享。Visual C++ 6.0中就提供這樣的編輯器,可「所見即所
得」地對這些不一樣類型的資源進行設計、編輯等。

 
4. 動態連接庫
動態連接庫提供了一些特定結構的函數,能被應用程序在運行過程當中裝
入和鏈接,且多個程序能夠共享同一個動態連接庫,這樣就能夠大大節
省內存和磁盤空間。從編程角度來講,動態連接庫能夠提升程序模塊的
靈活性,由於它自己是能夠單獨設計、編譯和調試的。
Windows提供了應用程序可利用的豐富的函數調用,大多數用於實現其
用戶界面和在顯示器上顯示的文本和圖形,都是經過動態連接庫來實現
的。這些動態連接庫是一些具備.DLL擴展名或者有時是.EXE擴展名的文
件。
在Windows操做系統中,最主要的DLL有KERNEL32.DLL、GDI32.DLL
和USER32.DLL三個模塊。其中,KERNEL32用來處理存儲器低層功
能、任務和資源管理等Windows核心服務; GDI32用來提供圖形設備接
口,管理用戶界面和圖形繪製,包括Windows元文件、位圖、設備描述
表和字體等;而USER32負責窗口的管理,包括消息、菜單、光標、計
時器以及其它與控制窗口顯示相關的一些功能。

 
5 . 進程和線程
在32位Windows多任務操做系統中,採用了進程和線程的管理模式。進程是裝入
內存中正在執行的應用程序。進程包括私有的虛擬地址空間、代碼、數據及其它
操做系統資源,如文件、管道以及對該進程可見的同步對象等。進程包括了一個
或多個在進程上下文內運行的線程。線程是操做系統分配CPU時間的基本實體。
線程能夠執行應用程序代碼的任何部分,包括當前正在被其它線程執行的那些部
分。同一進程的全部線程共享一樣的虛擬地址空間、全局變量和操做系統資源。
在一個應用程序中,能夠包括一個或多個進程,每一個進程由一個或多個線程構
成。


 
表3.1列出了一些在Windows編程中經常使用的基本數據類型

 編制一個MFC應用程序
 
前面的Ex_HelloMsg和Ex_HelloWin都是基於Windows API的C++應用程序。顯然,隨着應用程序的複雜性,C++應用程序代碼也必然越複雜。
爲了幫助用戶處理那些常用又複雜繁瑣的各類Windows操做,
Visual C++設計了一套基礎類庫(Microsoft Foundation Class Library,簡稱MFC)。MFC把Windows編程規範中的大多數內容封裝成爲各類類,
使程序員從繁雜的編程中解脫出來,提升了編程和代碼效率。

 
3.2.1 設計一個MFC程序
 
在理解MFC機制以前,先來看一個MFC應用程序。
[例Ex_HelloMFC] 一個MFC應用程序
#include <afxwin.h> // MFC頭文件
class CHelloApp : public CWinApp // 聲明應用程序類
{
  public:
   virtual BOOL InitInstance();
};
CHelloApp theApp; // 創建應用程序類的實例
class CMainFrame: public CFrameWnd // 聲明主窗口類
{
  public:
   CMainFrame()
   { // 建立主窗口
   Create(NULL, "個人窗口", WS_OVERLAPPEDWINDOW,      CRect(0,0,400,300));
}
  protected:
   afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
   DECLARE_MESSAGE_MAP()
}; 
 
// 消息映射入口
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_LBUTTONDOWN() // 單擊鼠標左鍵消息的映射宏
END_MESSAGE_MAP()
//定義消息映射函數
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
    MessageBox ("你好,個人Visual C++世界!", "問候", 0) ;
CFrameWnd::OnLButtonDown(nFlags, point);
}
BOOL CHelloApp::InitInstance()            // 每當應用程序首次執行時都要調用的初始化函數
{
       m_pMainWnd = new CMainFrame();
       m_pMainWnd->ShowWindow(m_nCmdShow);
       m_pMainWnd->UpdateWindow();
       return TRUE;


 
在Visual C++ 6.0運行上述MFC程序須要進行如下步驟:
(1) 選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在「工程」標籤頁面的列表
框中,選中Win32 Application項,建立一個Ex_HelloMFC空應用程序項目。
(2) 再次選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在文件標籤頁面左
邊的列表框中選擇C++ Source File項,在右邊的文件框中鍵入
Ex_HelloMFC.cpp,單擊[肯定]按鈕。
(3) 輸入上面的代碼。選擇「工程」→「設置」菜單命令,在出現的對話框中選擇
「General」標籤。而後在「Microsoft Foundation Classes」組合框中,選擇「Use
MFC in a Shared DLL」,如圖3.4所示。單擊[肯定]按鈕。
(4) 程序運行後,單擊鼠標左鍵,就會彈出一個對話框,結果同Ex_HelloWin

理解程序代碼
 
按照MFC的消息映射機制,映射一個消息的過程是由三個部分組成的:
(1) 在處理消息的類中,使用消息宏DECLARE_MESSAGE_MAP聲明對消息映射的支
持,並在該宏以前聲明消息處理函數。例如前面示例中的:
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
(2) 使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏在類聲明以後的地方定
義該類支持的消息映射入口點,全部消息映射宏都添加在這裏,固然不一樣的消息MFC
都會有不一樣的消息映射宏。例如:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

END_MESSAGE_MAP()
其中,BEGIN_MESSAGE_MAP帶有兩個參數,第一個參數用來指定須要支持消息映
射的用戶派生類,第二個參數指定該類的基類。
(3) 定義消息處理函數。例如:
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
       MessageBox ("你好,個人Visual C++世界!", "問候", 0) ;
   CFrameWnd::OnLButtonDown(nFlags, point);
}
 
3.3 使用MFC AppWizard
 
3.3.1應用程序框架類型
這些類型基本知足了各個層次的用戶的須要,但通常地,用戶更關心的是MFC AppWizard(exe)應用程序框架,由於它包含用戶最經常使用、最基本的三種應用程序類型:單文檔、多文檔和基於對話框的應用程序。 

建立一個單文檔應用程序
 
用MFC AppWizard(MFC應用程序嚮導)能夠方便地建立一個通用的Windows單文檔應用程
序,其步驟以下。
1. 開始
選擇「文件」→「新建」菜單,在彈出的「新建」對話框中,能夠看到工程標籤頁面中,顯示出一
系列的應用程序項目類型;選擇MFC AppWizard(exe)的項目類型(該類型用於建立可執行
的Windows應用程序),將項目工做文件夾定位在「D:\Visual C++ 6.0程序」,並在工程編輯
框中輸入項目名Ex_SDIHello,結果如圖

第一步
單擊[肯定]按鈕,出現如圖3.6所示的對話框,進行下列選擇:
(1)從應用程序類型單個文檔(SDI)、多重文檔(MDI)和基本對話框(基於對話框的
應用程序)中選擇「單個文檔」。
(2) 決定應用程序中是否須要MFC的文檔視圖(「文檔/查看體系結構支持」)結構的
支持。若不選定此項,則程序中的磁盤文件的打開、保存以及文檔和視圖的相互
做用等功能須要用戶來實現,且將跳過Step 2~Step 5,直接彈出「Step 6」對話
框。通常狀況下,應選中此項。
(3) 選擇資源所使用的語言,這裏是「中文[中國]」。
3.第二步
單擊[下一個]按鈕,出現如圖3.7所示的對話框,讓用戶選擇程序中是否加入數據
庫的支持(有關數據庫的內容將在之後的章節中介紹)。 

第三步
單擊[下一個]按鈕進入下一步,出現如圖3.8所示的對話框。容許用戶在程序中加入復
合文檔、自動化、ActiveX控件的支持。
5. 第四步
單擊[下一個]按鈕進入下一步,出現如圖3.9所示的對話框,對話框的前幾項依次肯定
對浮動工具條、打印與預覽以及通訊等特性的支持。

 第五步
保留以上默認值,單擊[下一個]按鈕進入下一步。彈出如圖3.10所示的對話框,這裏出現三
個方面的選項,供用戶來選擇:
(1) 應用程序的主窗口是MFC標準風格仍是窗口左邊有切分窗口的瀏覽器風格;
(2) 在源文件中是否加入註釋用來引導用戶編寫程序代碼;
(3) 使用動態連接庫仍是靜態連接庫。

第六步
保留默認選項,單擊[下一步]按鈕進行下一步,出現如圖3.11所示的對話框。在
這裏,用戶能夠對MFC AppWizard提供的默認類名、基類名、各個源文件名進
行修改。
單擊[完成]按鈕出現一個信息對話框,顯示出用戶在前面幾個步驟中做出的選擇
內容,單擊[肯定]按鈕系統開始建立,並又回到了Visual C++ 6.0的主界面。
8.編譯並運行
到這裏爲止,用戶雖然沒有編寫任何程序代碼,但MFC AppWizard已經根據用
戶的選擇內容自動生成基本的應用程序框架。單擊編譯工具欄上的運行工具按鈕
「」或按快捷鍵Ctrl+F5,系統開始編連並運行生成的單文檔應用程序可執行文件
Ex_SDIHello.exe,運行結果如圖3.12所示。

 MFC應用程序項目組織
 
1. 項目的文件組織
在Visual C++ 6.0中,項目中全部的源文件都是採用文件夾的方式進行管理的,它將
項目名做爲文件夾名,在此文件夾下包含源程序代碼文件(.cpp,.h)、項目文件(.dsp)以
及項目工做區文件(.dsw)等。表3.4列出了這些文件類型的的含義。

 

       


 
3.1 Windows編程基礎
編制一個功能強大和易操做的Windows應用程序所須要的代碼確定會比通常的C++程序要多得多,但並非全部的代碼都須要本身從頭開始編寫,由於Visual C++不只提供了經常使用的Windows應用程序的基本框架,並且能夠在框架程序中直接調用Win32 API(Application Programming
Interface, 應用程序接口)函數。這樣,用戶僅須要在相應的框架位置中添加本身的代碼或修改部分代碼就可實現Windows應用程序的許多功能。

 
3.1.1 簡單的Windows應用程序
 
先來看一個最簡單的Windows應用程序Ex_HelloMsg。
[例Ex_HelloMsg] 一個簡單的Windows應用程序
#include <windows.h>
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow)
{
     MessageBox (NULL, "你好,個人Visual C++世界!", "問候", 0) ;
     return 0 ;
}
在Visual C++ 6.0運行上述程序須要進行如下步驟:
(1) 選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在「工程」標籤頁面的列表框
中,選中Win32 Application項。
(2) 在工程編輯框中鍵入Win32應用程序項目名稱Ex_HelloMsg。在「位置」編輯框中直
接鍵入文件夾名稱,或單擊瀏覽按鈕選擇一個已有的文件夾。
(3) 單擊[肯定]按鈕繼續。一個詢問項目類型的Win32應用程序嚮導將被顯示,選中An
empty project項。單擊[完成]按鈕,系統將顯示該應用程序嚮導的建立信息,單擊[確
定]按鈕系統將自動建立此應用程序。
(4) 再次選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在「文件」標籤頁面左邊的
列表框中選擇C++ Source File項,在右邊的文件框中鍵入Ex_HelloMsg.cpp,單擊
[肯定]按鈕。

 
[例Ex_HelloMsg] 一個簡單的Windows應用程序
(5) 輸入上面的代碼,運行程序,結果如圖3.1所示。
從上面的程序能夠看出:
● C++控制檯應用程序以main函數做爲進入程序的初始入口點,但在Windows應用程
序中,main主函數被WinMain函數取代。WinMain函數的原型以下:
int WINAPI WinMain (
HINSTANCE hInstance, // 當前實例句柄
HINSTANCE hPrevInstance, // 前一實例句柄
LPSTR lpCmdLine, // 指向命令行參數的指針
int nCmdShow) // 窗口的顯示狀態

 
所謂句柄是一個標識Windows資源(如菜單、圖標、窗口等)和設備等對象的數據指針類型。一般,一個句柄變量可用來對系統中某些資源的間接引用。
●每個C++ Windows應用程序都須要Windows.h頭文件,它還包含了其餘的一些Windows頭文件。這些頭文件定義了Windows的全部數據類型、函數調用、數據結構和符號常量。
●程序中,MessageBox是一個Win32 API函數,用來彈出一個消息對話框。該函數第一個參數用來指定父窗口句柄,即對話框所在的窗口句柄。第2、三個參數分別用來指定顯示的消息內容和對話框窗口的標題,最後一個參數用來指定在對話框中顯示的按鈕。

 
[例Ex_HelloWin] 一個完整的Windows應用程序
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); // 窗口過程
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow)
{
     HWND       hwnd ; // 窗口句柄
     MSG        msg ; // 消息
     WNDCLASS wndclass ; // 窗口類
     wndclass.style  = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = "HelloWin"; // 窗口類名
     if (!RegisterClass (&wndclass)) 
 
{ // 註冊窗口
          MessageBox (NULL, "窗口註冊失敗!", "HelloWin", 0) ;    
          return 0 ;
}
 hwnd = CreateWindow ("HelloWin",                 // 窗口類名
                          "個人窗口", // 窗口標題
                          WS_OVERLAPPEDWINDOW,    // 窗口樣式
                          CW_USEDEFAULT,              // 窗口最初的 x 位置
                          CW_USEDEFAULT,              // 窗口最初的 y 位置
                          CW_USEDEFAULT,              // 窗口最初的 x 大小
                          CW_USEDEFAULT,              // 窗口最初的 y 大小
                          NULL,                       // 父窗口句柄
                          NULL,                       // 窗口菜單句柄
                          hInstance,                  // 應用程序實例句柄
                          NULL) ;                     // 建立窗口的參數
     ShowWindow (hwnd, nCmdShow) ; // 顯示窗口
     UpdateWindow (hwnd) ; // 更新窗口,包括窗口的客戶區
     // 進入消息循環:當從應用程序消息隊列中檢取的消息是WM_QUIT時,則退出循環。
     while (GetMessage (&msg, NULL, 0, 0))
    {
TranslateMessage (&msg) ; // 轉換某些鍵盤消息
         DispatchMessage (&msg) ; // 將消息發送給窗口過程,這裏是WndProc
     } 
 
}
     return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
     switch (message)
     {
case WM_CREATE:   // 窗口建立產生的消息
return 0 ;         
case WM_LBUTTONDOWN:
MessageBox (NULL, "你好,個人Visual C++世界!", "問候", 0) ;
  return 0 ;         
case WM_DESTROY: // 當窗口關閉時產生的消息
  PostQuitMessage (0) ;
  return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;    // 執行默認的消息處理
}

 
程序運行後,單擊鼠標左鍵,就會彈出一個對話框,結果如圖3.2所示

 
窗口過程函數WndProc用來接收和處理各類不一樣的消息,而主函數WinMain一般要完成如下幾步工做:
(1) 調用API函數RegisterClass註冊應用程序的窗口類。
(2) 調用相關API函數建立和顯示窗口,並進行其它必要的初始化處理。其中,函數CreateWindow用來建立已註冊窗口類的窗口。Windows每個窗口都有一些基本屬性,如窗口標題、窗口位置和大小、應用程序圖標、鼠標指針、菜單和背景顏色等。窗口類就是充當這些屬性的模板。
(3) 建立和啓動應用程序的消息循環。Windows應用程序接受各類不一樣的消息,包括鍵盤消息、鼠標以及窗口產生的各類消息。Windows系統首先將消息放入消息隊列中,應用程序的消息循環就是從應用程序的消息隊列中檢取消息,並將消息發送相應的窗口過程函數中做進一步處理。API函數GetMessage 和DispatchMessage就是起到這樣的做用。
(4) 若是接收到WM_QUIT消息,則退出應用程序。

 
圖3.3  Windows應用程序的基本流程

 

第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索

   
3.1.2 Windows編程特色

一個完整的Windows應用程序除了WinMain函數外,還包含用於處理用戶動做和
窗口消息的窗口函數。這不一樣於一個C++的控制檯應用程序,能夠將整個程序包
含在main函數中。事實上,它們的區別還遠不止這些,不久還會發現一個
Windows應用程序還經常具備這樣的一些特性:
● 消息驅動機制
●圖形設備接口(GDI)
●基於資源的程序設計
●動態連接庫
●進程和線程

 

 
1. 消息驅動機制
在Windows操做環境中,不管是系統產生的動做或是用戶運行應用程序產生的動
做,都稱爲事件(Events)產生的消息(Message)。例如,在Windows 桌面(傳統風
格)上,雙擊應用程序的快捷圖標,系統就會執行該應用程序。在Windows的應
用程序中,也是經過接收消息、分發消息、處理消息來和用戶進行交互的。
這種消息驅動的機制是Windows編程的最大特色。須要注意的是,許多Windows
消息都通過了嚴格的定義,而且適用於全部的應用程序。例如,當用戶按下鼠標
的左鍵時系統就會發送WM_LBUTTONDOWN消息,而當用戶敲了一個字符鍵時
系統就會發送WM_CHAR消息,若用戶進行菜單選擇或工具按鈕單擊等操做時,
系統又會相應地發送WM_COMMAND消息給相應的窗口等等。

 
2. 圖形設備接口(GDI)
在傳統的DOS環境中,想要在打印機上打印一幅圖形是一件很是複雜的事情,因
爲用戶必須根據打印機類型和指令規則向打印機輸送數據。而Windows則提供了
一個抽象的接口,稱爲圖形設備接口(Graphical Device Interface,簡稱GDI),
使得用戶直接利用系統的GDI函數就能方便實現輸入或輸出,而沒必要關心與系統
相連的外部設備的類型。
3. 基於資源的程序設計
Windows應用程序經常包含衆多圖形元素,例如光標、菜單、工具欄、位圖、對
話框等,在Windows環境下,每個這樣的元素都做爲一種能夠裝入應用程序的
資源來存放。這些資源就像C++程序中的常量同樣,能夠被編輯、修改,也能夠
被其餘應用程序所共享。Visual C++ 6.0中就提供這樣的編輯器,可「所見即所
得」地對這些不一樣類型的資源進行設計、編輯等。

 
4. 動態連接庫
動態連接庫提供了一些特定結構的函數,能被應用程序在運行過程當中裝
入和鏈接,且多個程序能夠共享同一個動態連接庫,這樣就能夠大大節
省內存和磁盤空間。從編程角度來講,動態連接庫能夠提升程序模塊的
靈活性,由於它自己是能夠單獨設計、編譯和調試的。
Windows提供了應用程序可利用的豐富的函數調用,大多數用於實現其
用戶界面和在顯示器上顯示的文本和圖形,都是經過動態連接庫來實現
的。這些動態連接庫是一些具備.DLL擴展名或者有時是.EXE擴展名的文
件。
在Windows操做系統中,最主要的DLL有KERNEL32.DLL、GDI32.DLL
和USER32.DLL三個模塊。其中,KERNEL32用來處理存儲器低層功
能、任務和資源管理等Windows核心服務; GDI32用來提供圖形設備接
口,管理用戶界面和圖形繪製,包括Windows元文件、位圖、設備描述
表和字體等;而USER32負責窗口的管理,包括消息、菜單、光標、計
時器以及其它與控制窗口顯示相關的一些功能。

 
5 . 進程和線程
在32位Windows多任務操做系統中,採用了進程和線程的管理模式。進程是裝入
內存中正在執行的應用程序。進程包括私有的虛擬地址空間、代碼、數據及其它
操做系統資源,如文件、管道以及對該進程可見的同步對象等。進程包括了一個
或多個在進程上下文內運行的線程。線程是操做系統分配CPU時間的基本實體。
線程能夠執行應用程序代碼的任何部分,包括當前正在被其它線程執行的那些部
分。同一進程的全部線程共享一樣的虛擬地址空間、全局變量和操做系統資源。
在一個應用程序中,能夠包括一個或多個進程,每一個進程由一個或多個線程構
成。


 
表3.1列出了一些在Windows編程中經常使用的基本數據類型

 

第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索

 

 
表3.2列出了經常使用的預約義句柄,它們的類型均爲void *,即一個32位指針。

第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索

  
3.2 編制一個MFC應用程序
 
前面的Ex_HelloMsg和Ex_HelloWin都是基於Windows API的C++應用程序。顯然,隨着應用程序的複雜性,C++應用程序代碼也必然越複雜。
爲了幫助用戶處理那些常用又複雜繁瑣的各類Windows操做,
Visual C++設計了一套基礎類庫(Microsoft Foundation Class Library,簡稱MFC)。MFC把Windows編程規範中的大多數內容封裝成爲各類類,
使程序員從繁雜的編程中解脫出來,提升了編程和代碼效率。

 
3.2.1 設計一個MFC程序
 
在理解MFC機制以前,先來看一個MFC應用程序。
[例Ex_HelloMFC] 一個MFC應用程序
#include <afxwin.h> // MFC頭文件
class CHelloApp : public CWinApp // 聲明應用程序類
{
  public:
   virtual BOOL InitInstance();
};
CHelloApp theApp; // 創建應用程序類的實例
class CMainFrame: public CFrameWnd // 聲明主窗口類
{
  public:
   CMainFrame()
   { // 建立主窗口
   Create(NULL, "個人窗口", WS_OVERLAPPEDWINDOW,      CRect(0,0,400,300));
}
  protected:
   afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
   DECLARE_MESSAGE_MAP()
}; 
 
// 消息映射入口
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_LBUTTONDOWN() // 單擊鼠標左鍵消息的映射宏
END_MESSAGE_MAP()
//定義消息映射函數
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
    MessageBox ("你好,個人Visual C++世界!", "問候", 0) ;
CFrameWnd::OnLButtonDown(nFlags, point);
}
BOOL CHelloApp::InitInstance()            // 每當應用程序首次執行時都要調用的初始化函數
{
       m_pMainWnd = new CMainFrame();
       m_pMainWnd->ShowWindow(m_nCmdShow);
       m_pMainWnd->UpdateWindow();
       return TRUE;


 
在Visual C++ 6.0運行上述MFC程序須要進行如下步驟:
(1) 選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在「工程」標籤頁面的列表
框中,選中Win32 Application項,建立一個Ex_HelloMFC空應用程序項目。
(2) 再次選擇「文件」→「新建」菜單命令,顯示出「新建」對話框。在文件標籤頁面左
邊的列表框中選擇C++ Source File項,在右邊的文件框中鍵入
Ex_HelloMFC.cpp,單擊[肯定]按鈕。
(3) 輸入上面的代碼。選擇「工程」→「設置」菜單命令,在出現的對話框中選擇
「General」標籤。而後在「Microsoft Foundation Classes」組合框中,選擇「Use
MFC in a Shared DLL」,如圖3.4所示。單擊[肯定]按鈕。
(4) 程序運行後,單擊鼠標左鍵,就會彈出一個對話框,結果同Ex_HelloWin

第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
 
3.2.2 理解程序代碼
 
按照MFC的消息映射機制,映射一個消息的過程是由三個部分組成的:
(1) 在處理消息的類中,使用消息宏DECLARE_MESSAGE_MAP聲明對消息映射的支
持,並在該宏以前聲明消息處理函數。例如前面示例中的:
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
(2) 使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏在類聲明以後的地方定
義該類支持的消息映射入口點,全部消息映射宏都添加在這裏,固然不一樣的消息MFC
都會有不一樣的消息映射宏。例如:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

END_MESSAGE_MAP()
其中,BEGIN_MESSAGE_MAP帶有兩個參數,第一個參數用來指定須要支持消息映
射的用戶派生類,第二個參數指定該類的基類。
(3) 定義消息處理函數。例如:
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
       MessageBox ("你好,個人Visual C++世界!", "問候", 0) ;
   CFrameWnd::OnLButtonDown(nFlags, point);
}
 
3.3 使用MFC AppWizard
 
3.3.1應用程序框架類型
這些類型基本知足了各個層次的用戶的須要,但通常地,用戶更關心的是MFC AppWizard(exe)應用程序框架,由於它包含用戶最經常使用、最基本的三種應用程序類型:單文檔、多文檔和基於對話框的應用程序。

 

第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索

  
3.3.2 建立一個單文檔應用程序
 
用MFC AppWizard(MFC應用程序嚮導)能夠方便地建立一個通用的Windows單文檔應用程
序,其步驟以下。
1. 開始
選擇「文件」→「新建」菜單,在彈出的「新建」對話框中,能夠看到工程標籤頁面中,顯示出一
系列的應用程序項目類型;選擇MFC AppWizard(exe)的項目類型(該類型用於建立可執行
的Windows應用程序),將項目工做文件夾定位在「D:\Visual C++ 6.0程序」,並在工程編輯
框中輸入項目名Ex_SDIHello,結果如圖3.5所示。

第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
 
2. 第一步
單擊[肯定]按鈕,出現如圖3.6所示的對話框,進行下列選擇:
(1)從應用程序類型單個文檔(SDI)、多重文檔(MDI)和基本對話框(基於對話框的
應用程序)中選擇「單個文檔」。
(2) 決定應用程序中是否須要MFC的文檔視圖(「文檔/查看體系結構支持」)結構的
支持。若不選定此項,則程序中的磁盤文件的打開、保存以及文檔和視圖的相互
做用等功能須要用戶來實現,且將跳過Step 2~Step 5,直接彈出「Step 6」對話
框。通常狀況下,應選中此項。
(3) 選擇資源所使用的語言,這裏是「中文[中國]」。
3.第二步
單擊[下一個]按鈕,出現如圖3.7所示的對話框,讓用戶選擇程序中是否加入數據
庫的支持(有關數據庫的內容將在之後的章節中介紹)。

 

第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
 
4.第三步
單擊[下一個]按鈕進入下一步,出現如圖3.8所示的對話框。容許用戶在程序中加入復
合文檔、自動化、ActiveX控件的支持。
5. 第四步
單擊[下一個]按鈕進入下一步,出現如圖3.9所示的對話框,對話框的前幾項依次肯定
對浮動工具條、打印與預覽以及通訊等特性的支持。
第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
 
第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
 
 
6. 第五步
保留以上默認值,單擊[下一個]按鈕進入下一步。彈出如圖3.10所示的對話框,這裏出現三
個方面的選項,供用戶來選擇:
(1) 應用程序的主窗口是MFC標準風格仍是窗口左邊有切分窗口的瀏覽器風格;
(2) 在源文件中是否加入註釋用來引導用戶編寫程序代碼;
(3) 使用動態連接庫仍是靜態連接庫。
第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
 
 
7. 第六步
保留默認選項,單擊[下一步]按鈕進行下一步,出現如圖3.11所示的對話框。在
這裏,用戶能夠對MFC AppWizard提供的默認類名、基類名、各個源文件名進
行修改。
單擊[完成]按鈕出現一個信息對話框,顯示出用戶在前面幾個步驟中做出的選擇
內容,單擊[肯定]按鈕系統開始建立,並又回到了Visual C++ 6.0的主界面。
8.編譯並運行
到這裏爲止,用戶雖然沒有編寫任何程序代碼,但MFC AppWizard已經根據用
戶的選擇內容自動生成基本的應用程序框架。單擊編譯工具欄上的運行工具按鈕
「」或按快捷鍵Ctrl+F5,系統開始編連並運行生成的單文檔應用程序可執行文件
Ex_SDIHello.exe,運行結果如圖3.12所示。
第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
 
第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
   
3.3.3 MFC應用程序項目組織
 
1. 項目的文件組織
在Visual C++ 6.0中,項目中全部的源文件都是採用文件夾的方式進行管理的,它將
項目名做爲文件夾名,在此文件夾下包含源程序代碼文件(.cpp,.h)、項目文件(.dsp)以
及項目工做區文件(.dsw)等。表3.4列出了這些文件類型的的含義。
第3章 MFC基本應用程序的創建 - 追逐 - 路漫漫其修遠兮,吾將上下而求索
  
除了上述文件外,還有相應的Debug(調試)或Release(發行)、Res(資源)等子文
件夾。例如上述建立的單文檔應用程序項目Ex_SDIHello,其各文件的組織如圖
3.13所示。固然,不一樣類型的項目的文件類型及數目會有所不一樣。

 MFC類結構
在開發環境中,Visual C++ 6.0是經過左邊的項目工做區窗口來對項目進行各類管理。項目
工做區窗口包含3個頁面,它們分別是ClassView頁、ResourceView頁和FileView頁,經過
單擊項目區窗口底部的頁面標籤進行切換。
將Visual C++ 6.0項目工做區窗口切換到ClassView頁面,能夠看到MFC爲單文檔應用程序
項目Ex_SDIHello自動建立了類CAboutDlg、CEx_SDIHelloApp、 CEx_SDIHelloDoc、
CEx_SDIHelloView和CMainFrame。這些MFC類之間的繼承和派生關係如圖3.14所示

 使用類嚮導
 
MFC類嚮導(ClassWizard)是Visual C++ 6.0中又一個很是有用的工具。
它能自動爲一個項目添加一個類、進行消息和數據映射、建立OLE
Automation(自動化)屬性和方法以及進行ActiveX事件處理等。 
 
3.4.1 類嚮導概述
 
打開MFC類嚮導可使用下列幾種方法:
(1) 選擇「查看」→「創建類嚮導」菜單或直接使用Ctrl+W快捷鍵。
(2) 在源代碼文件的文檔編輯窗口中,右擊鼠標,從彈出的快捷菜單中選擇「創建
類嚮導」命令。
當MFC類嚮導打開後,就會彈出如圖3.15所示的MFC ClassWizard對話框

能夠看到ClassWizard對話框包含了5個標籤頁面,它們各自含義以下:
● Message Maps(消息映射):用來添加、刪除和編程處理消息的成員函數。
● Member Variables(成員變量):添加或刪除與控件相關聯的成員變量(或稱數據
成員),以便與控件進行數據交換。這些控件所在的類通常是從CDialog、
CPropertyPage、CRecordView或CDaoRecordView中派生的類。
● Automation(自動化):爲支持Automation的類(如ActiveX控件類)添加屬性和方
法。
● ActiveX Events(ActiveX事件):爲ActiveX控件類添加觸發事件的支持。
● Class Info(類信息):有關項目中類的其餘信息。
通常來講,MFC ClassWizard對話框最前兩項是用戶最關心的,也是最常用
的,由於幾乎全部的代碼編寫都要利用這兩個標籤項。因爲Member Variables功
能之後還會詳細討論,所以這裏僅討論Message Maps(消息映射)與類的添加和
刪除方法。
  
3.4.2 消息和消息映射

  
1. 消息分類
Windows應用程序中的消息主要有三種類型。
(1)窗口消息(Windows message)。這類消息主要是指由WM_開頭的消息(WM_
COMMAND除外),通常由窗口類和視圖類對象來處理。窗口消息每每帶有參
數,以標誌處理消息的方法。
(2)控件的通知消息(Control notifications)。當控件的狀態發生改變(例如用戶在控
件中進行輸入)時,控件就會向其父窗口發送WM_COMMAND通知消息。應用程
序框架處理控件消息的方法和窗口消息相同,但按鈕的BN_CLICKED通知消息
除外,它的處理方法與命令消息相同。
(3)命令消息(Command message)。命令消息主要包括由用戶交互對象(菜單、工
具條的按鈕、快捷鍵等)發送的WM_COMMAND通知消息。命令消息的處理方式
與其餘兩種消息不一樣,它可以被多種對象接收、處理,這些對象包括文檔類、文
檔模板類、應用程序自己以及窗口和視類等;而窗口消息和控件的通知消息是由
窗口對象接收並處理的,這裏的窗口對象是指從CWnd中派生的類的對象,它包
括CFrameWnd、CMDIFrameWnd、CMDIChildWnd、CView、CDialog以及從
這些類派生的對象等。 
 
2. ClassWizard映射消息的通常方法
在MFC中,絕大多數消息均可由MFC的ClassWizard來映射。將ClassWizard對
話框切換到Message Maps頁面(參看圖3.15),能夠看到它有許多選項,如項目
組合框、類組合框等。各項功能說明如表3.5所示。

. ClassWizard映射消息的通常方法
例如,若向CEx_SDIHelloView中添加WM_LBUTTOMDOWN的消息映射,則可按下列步
驟進行:
(1) 按Ctrl+W快捷鍵打開MFC ClassWizard對話框。
(2) 在Class name組合框中,將類名選定爲CEx_SDIHelloView。此時,Object IDs和
Messages列表內容會相應的改變。
(3) 在Object IDs列表框中選定CEx_SDIHelloView,而在Messages列表中選定
WM_LBUTTOMDOWN消息。
(4) 雙擊Messages列表中的WM_LBUTTOMDOWN消息或單擊[Add Function]按鈕,都會在
CEx_SDIHelloView類中添加該消息的映射函數OnLButtonDown,同時在Member funcions
列表中顯示這一消息映射函數和被映射的消息,結果如圖3.16所示。
(5) 單擊[Edit Code]按鈕後,ClassWizard對話框退出,並轉向文檔窗口,定位到
OnLButtonDown函數源代碼處。
(6) 添加下列代碼:
void CEx_SDIHelloView::OnLButtonDown(UINT nFlags, CPoint point)
{
         MessageBox ("你好,個人Visual C++世界!", "問候", 0) ;
CView::OnLButtonDown(nFlags, point);
}
(7) 這樣就完成了一個消息映射過程。程序運行後,在窗口客戶區單擊鼠標左鍵,就會彈出
一個消息對話框。

 消息映射代碼
查看CEx_SDIHelloView程序代碼,能夠發現:ClassWizard爲WM_LBUTTOMDOWN
的消息映射做了如下三個方面內容的安排:
(1) 在頭文件Ex_SDIHelloView.h中聲明消息處理函數OnLButtonDown:
protected:
//{{AFX_MSG(CEx_SDIHelloView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
代碼中的//{{AFX_MSG(CEx_SDIHelloView)和//}}AFX_MSG之間的部分是ClassWizard
定義的專門用做消息映射函數聲明的標記。表示該程序塊中的消息映射聲明是由
ClassWizard來自動管理的,用戶通常不須要去更改。須要說明的是,凡//{{和//}}之間
的程序代碼塊均由ClassWizard自動管理。 
 
3. 消息映射代碼
(2) 在Ex_SDIHelloView.cpp源文件前面的消息映射入口處,添加了相應的映射宏:
BEGIN_MESSAGE_MAP(CEx_SDIHelloView, CView) // 消息映射開始
//{{AFX_MSG_MAP(CEx_SDIHelloView)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP

END_MESSAGE_MAP() // 消息映射結束
(3) 在Ex_SDIHelloView.cpp文件中寫入一個空的消息處理函數的模板,以便用戶填入
具體代碼,以下面的框架:
void CEx_SDIHelloView::OnLButtonDown(UINT nFlags, CPoint point)
{ // TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
事實上,根據ClassWizard產生的上述消息映射過程,用戶能夠本身手動添加一些
MFC ClassWizard不支持的消息映射函數,以完成特定的功能。例如,Ex_HelloMFC
示例就是按照上述過程添加消息映射的。 
 
4. 鍵盤消息
當用戶按下一個鍵或組合鍵時,Windows將WM_KEYDOWN或WM_SYSKEYDOWN
放入具備輸入焦點的應用程序窗口的消息隊列中。當鍵被釋放時,Windows則把
WM_KEYUP或WM_SYSKEYUP消息放入消息隊列中。對於字符鍵來講,還會在這
兩個消息之間產生WM_CHAR消息。
MFC ClassWizard能自動添加了當前類的WM_KEYDOWN和WM_KEYUP擊鍵消息
處理函數的調用,它們具備下列函數原型:
afx_msg void OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags );
afx_msg void OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags );
afx_msg是MFC用於定義消息函數的標誌,參數nChar表示虛擬鍵代碼,nRepCnt表
示當用戶按住一個鍵時的重複計數,nFlags表示擊鍵消息標誌。
所謂虛擬鍵代碼,是指與設備無關的鍵盤編碼。在Visual C++中,最經常使用的虛擬鍵代
碼已被定義在Winuser.h中,例如:VK_SHIFT表示SHIFT鍵,VK_F1表示功能鍵F1
等。
同擊鍵消息同樣,MFC中的ClassWizard也提供相應的字符消息處理框架,並自動添
加了當前類的WM_CHAR消息處理函數調用,它具備下列函數原型:
afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );
參數nChar表示鍵的ASCII碼,nRepCnt表示當用戶按住一個鍵時的重複計數,
nFlags表示字符消息標誌。 

 
5. 鼠標消息
當用戶對鼠標進行操做時,像鍵盤同樣也會產生對應的消息。一般,Windows只
將鍵盤消息發送給具備輸入焦點的窗口,但鼠標消息不受這種限制。只要鼠標移
過窗口的客戶區時,就會向該窗口發送WM_MOUSEMOVE(移動鼠標)消息。
這裏的客戶區是指窗口中用於輸出文檔的區域。因爲MFC頭文件中定義的與鼠標
按鈕相關的標識使用了LBUTTON(左)、MBUTTON(中)和RBUTTON(右),於是
當在窗口的客戶區中按下或釋放一個鼠標鍵時,還會產生如表3.6所示的消息

鼠標消息
對於全部這些消息來講,ClassWizard都會將映射成相似afx_msg void OnXXXX
的消息處理函數,如前面WM_LBUTTONDOWN的消息函數OnLButtonDown,
它們具備函數原型:
afx_msg void OnXXXX( UINT nFlags, CPoint point );
其中,point表示鼠標光標在屏幕的(x,y)座標;nFlags表示鼠標按鈕和鍵盤組合情
況,它能夠是下列值的組合(MK前綴表示「鼠標鍵」):
● MK_CONTROL —— 鍵盤上的Ctrl鍵被按下
● MK_LBUTTON —— 鼠標左按鈕被按下
● MK_MBUTTON —— 鼠標中按鈕被按下
● MK_RBUTTON —— 鼠標右按鈕被按下
● MK_SHIFT    —— 鍵盤上的Shift鍵被按下
若想知道某個鍵被按下,可用對應的標識與nFlags進行邏輯「與」(&)運算,所得結
果若爲TRUE(非0)時,則表示該鍵被按下。例如,若收到了
WM_LBUTTONDOWN消息,且值nFlags&MK_CONTROL是TRUE時,則代表
按下鼠標左鍵的同時也按下Ctrl鍵。

  
6. 計時器消息
應用程序是經過CWnd的SetTimer函數來設置並啓動計時器的,這個函數的原型以下:
    UINT SetTimer( UINT nIDEvent, UINT nElapse,
                       void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );
參數nIDEvent用來指定該計時器的標識值(不能爲0),當應用程序須要多個計時器時可屢次
調用該函數,但每個計時器的標識值應是惟一的,各不相同。nElapse表示計時器的時
間間隔(單位爲毫秒),lpfnTimer是一個回調函數的指針,該函數由應用程序來定義,用來
處理計時器WM_TIMER消息。通常狀況下該參數爲NULL,此時WM_TIMER消息被放入到
應用程序消息隊列中供CWnd對象處理。
SetTimer函數成功調用後返回新計時器的標識值。當應用程序再也不使用計時器時,可調用
CWnd:: KillTimer函數來中止WM_TIMER消息的傳送,其函數原型以下:
    BOOL KillTimer( int nIDEvent );
其中nIDEvent和用戶調用SetTimer函數設置的計時器標識值是一致的。
對於WM_TIMER消息,ClassWizard會將其映射成具備下列原型的消息處理函數:
    afx_msg void OnTimer( UINT nIDEvent );
經過nIDEvent可判斷出WM_TIMER是哪一個計時器傳送的。 

 
7. 其餘窗口消息
在系統中,除了用戶輸入產生的消息外,還有許多系統根據應用程序的狀態和運
行過程產生的消息,有時也須要用戶進行處理。
(1) WM_CREATE消息。該消息是在窗口對象建立後,Windows向視圖發送的第
一個消息;若是用戶有什麼工做須要在初始化時處理,就可在該消息處理函數中
加入所需代碼。可是,因爲WM_CREATE消息發送時,窗口對象還未完成,窗
口還不可見,所以在該消息處理函數
OnCreate內,不能調用那些依賴於窗口處於完成激活狀態的Windows函數,如
窗口的繪圖函數等。
(2) WM_CLOSE或WM_DESTROY消息。當用戶從系統菜單中關閉窗口或者父
窗口被關閉時,Windows都會發送WM_CLOSE消息;而WM_DESTROY消息是
在窗口從屏幕消失後發送的,所以它緊隨WM_CLOSE以後。
(3) WM_PAINT消息。當窗口的大小發生變化、窗口內容發生變化、窗口間的層
疊關係發生變化或調用函數UpdateWindow或RedrawWindow時,系統都將產生
WM_PAINT消息,表示要從新繪製窗口的內容。該消息處理函數的原型是;
          afx_msg void OnPaint();
用ClassWizard映射該消息的目的是執行本身的圖形繪製代碼 。

 
3.4.3 類的添加和刪除
 
1. 類的添加
給項目添加一個類有不少方法,例如選擇「工程」→「添加工程」→「Files」菜單命令,
可將外部源文件所定義的類添加到項目中。可是若是使用MFC的ClassWizard,
就能夠從大多數MFC類中派生一個類,而且建立的類代碼自動包含MFC所必需
的消息映射等機制。
用MFC ClassWizard給項目添加一個類一般是按下列步驟進行的:
(1) 按快捷鍵Ctrl+W啓動MFC ClassWizard對話框。單擊[Add Class]按鈕,從彈
出的下拉菜單中選擇New命令,彈出如圖3.17所示的New Class對話框。
(2) 對話框中,Name是用來輸入用戶定義的類名,注意要以「C」字母打頭,以保
持與MFC標識符命名規則一致;File Name是該類的源代碼文件名,單擊
[Change]按鈕可改變源文件名稱及其在磁盤中的位置;Base class用來指定該類
的基類;Dialog ID是當選擇CDialog做爲基類時指定對話框的資源ID號。最下面
的Automation是用來設置對自動化的支持。
(3) 單擊[OK]按鈕,一個新類就會自動添加到項目中。 
 
類的添加

類的刪除
當添加的類須要刪除時,則須要按下列步驟進行:
將Visual C++ 6.0打開的全部文檔窗口關閉。
將項目工做區窗口切換到FileView頁面,展開Source Files和Header Files結點,
分別選定要刪除類的對應.h和.cpp文件,按下Delete鍵,刪除這兩個文件。
選擇「文件」→「關閉工做區」菜單命令,關閉項目。
從實際的文件夾中刪除對應的.h和.cpp文件與.clw文件。
這樣,當調入項目文件後,按Ctrl+W快捷鍵就會彈出一個對話框,詢問是否從新
創建ClassWizard數據文件,單擊[是]按鈕,出現如圖3.18所示的Select Source
Files對話框。單擊右下的[Add All]按鈕便可將.h和.cpp所包含的類刪除

總而言之,MFC編程仍是多實踐。相信你是mfc編程高手

相關文章
相關標籤/搜索