VC 課程之以 MFC 建立程式 葉建榮 巨匠電腦台北東區認證中心
建立基本視窗程式 Hello! -  您的第一個視窗程式 CWndApp 類別與程式進入點 視窗框架物件的建立
您的第一個視窗程式 使用 MFC 撰寫視窗程式時,必須載入 afxwin 標頭檔。該標頭檔定義了所有 MFC 類別,因此,所有視窗程式都必須載入 afxwin 標頭檔。 當想要建立一個什麼都不做的視窗框架時,必須建立兩種物件,一個是 應用程式物件 ,另一個是 視窗框架物件 。前者代表整個應用程式,後者代表應用程式介面。
您的第一個視窗程式 撰寫視窗程式時,必須用繼承的方式,運用 MFC 的類別 ( 其實就是直接拿類別來建立物件 ) 。 應用程式物件與視窗框架物件都必須借用 MFC 的類別才能建立。如建立應用程式類別時,需繼承 CWndApp 類別,建立視窗框架物件則需利用 CFrameWnd 類別。
標頭檔 #include <afxwin.h> 應用程式物件與視窗框架物件 CWinApp CFrameWnd 您的第一個視窗程式
Hello 程式範例建立出的視窗程式相當簡單,只是一個空白的視窗框架。 透過這個程式範例將介紹以下重點: CWndApp 類別與程式進入點 視窗框架物件的建立 您的第一個視窗程式
CWndApp 類別與程式進入點 自訂應用程式類別   -  要完成自訂應用程式類別的建立,所需要完成的工作如下:  繼承 CWndApp 類別 重載 CWndApp::InitInstance 函數,此函數為視窗程式的進入點,回傳值的型態為 BOOL 。 class MyApp : public CWinApp // 繼承 CWinApp {public: BOOL InitInstance() // 程式進入點 { … } };
CWndApp::m_pMainWnd 屬性   -  自訂應用程式類別除了必須過載繼承於 CWndApp 類別的 InitInstance 函數外,還繼承了 CWndApp 類別的 m_pMainWnd 屬性,這個屬性將指向應用程式物件所使用的視窗框架物件,在 CWndApp::InitInstance 函數中將會設定該屬性。 CWndApp 類別與程式進入點
程式的進入點 (CWndApp::InitInstance 函數 ) –  當繼承 CWndApp 類別建立應用程式類別時,必須重載 CWndApp::InitInstance 函數,做為視窗程式的進入點。 通常在該函數中,將完成以下的工作: 產生視窗框架物件 將該視窗框架物件的指標,設定給 CWndApp::m_pMainWnd 屬性。 在螢幕中建立視窗框架 顯示視窗框架物件。 CWndApp 類別與程式進入點
BOOL InitInstance() // 程式進入點 { // 建立 CFrameWnd 物件 CFrameWnd *Frame = new CFrameWnd(); m_pMainWnd = Frame; // 將 m_pMainWnd 設定為 Frame   Frame->Create(NULL,&quot;Hello MFC&quot;); // 建立視窗   Frame->ShowWindow(SW_SHOW);  // 顯示視窗 return true; } CWndApp 類別與程式進入點
完成應用程式類別的自訂後,必須在程式裡, 建立應用程式物件 。建立該物件時,將會呼叫 InitInstance 函數,進入程式的進入點。  MyApp a_app; 建立一個應用程式物件, MyApp 為 自訂的應用程式類別 CWndApp 類別與程式進入點
Template Method Design Pattern CWndApp 類別與程式進入點 CWinApp MyApp Run( ) InitInstance( )
視窗框架物件 視窗框架物件就是您在電腦螢幕上看到的視窗。在剛剛的程式範例裡,將直接利用 CFrameWnd 類別建立一個供應用程式物件建立的視窗框架物件。
由 CFrameWnd 類別所建立的視窗框架物件,提供了基本視窗所具備的功能,如 系統選單 及右上角的三個 視窗控制按鈕。 視窗框架物件 系統選單 視窗控制按鈕
產生視窗框架物件與建立、顯示視窗,並不是同一件事,因為在視窗程式裡,產生一個視窗框架物件,是指在程式裡建立了一個視窗框架物件,當在程式裡,需要操作視窗框架時,我們可以直接操作該物件。 建立一個視窗框架物件,則是指利用 CFrameWnd::Create 函數,向作業系統註冊了這個視窗框架。經過了視窗框架的產生、建立的過程後,才能利用 CFrameWnd::ShowWindow 函數,將視窗顯示在螢幕上。 視窗框架物件
BOOL InitInstance() // 程式進入點 { CFrameWnd *Frame = new CFrameWnd(); // 建立 CFrameWnd 物件   m_pMainWnd = Frame; // 將 m_pMainWnd 設定為 Frame Frame->Create(NULL,&quot;Hello MFC&quot;); // 建立視窗   Frame->ShowWindow(SW_SHOW);  // 顯示視窗   return true; } 產生、建立、顯示視窗框架物件
BOOL virtual CFrameWnd::Create( LPCTSTR lpszClassName,  LPCTSTR lpszWindowName, DWORD dwStyle =  WS_OVERLAPPEDWINDOW, const RECT& rect = rectDefault, CWnd* pParentWnd = NULL, LPCTSTR lpszMenuName = NULL, DWORD dwExStyle = 0, CCreateContext* pContext = NULL ); 建立視窗框架的函數
八個參數中的後六個參數都有預設值,只有前兩個參數必須指定。 第一個參數 lpszClassName  指定 WNDCLASS 視窗類別,放置 NULL 是要以  MFC  內建的視窗類別產生一個標準的外框視窗。 第二個參數  lpszWindowName  指定視窗標題。 建立視窗框架的函數
第三個參數 dwStyle 指定視窗風格 (Windows Stylus) ,預設是 WS_OVERLAPPEDWINDOW ,是最常用的一種,它被定義為 ( 在  WINDOWS.H  之中 ) : #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) 視窗風格 (Windows Stylus) 的參數如下表所示: 建立視窗框架的函數
Window Styles  建立一個視窗時,即將該視窗宣告為不可接收任何訊息。 WS_DISABLED 建立雙外框,但沒有標題的的視窗。 WS_DLGFRAME 當子視窗收到一個重繪訊息時,將不會重繪被其他子視窗覆蓋的部份。 WS_CLIPSIBLINGS 將視窗設定為第一個控制項,通常用於由控制項群組所組成的對話盒視窗,並可利用方向鍵在控制項間移動。 WS_GROUP 當在父視窗中繪圖時,繼會避開被子視窗遮蓋的部份不畫。 WS_CLIPCHILDREN 此祝窗為子視窗,但不能與 WS_POPUP 並用。 WS_CHILD 有標題欄 ( 含 WS_BORDER) ,但不可與 WS_DLGFRAME 樣式並用。 WS_CAPTION 有外框。 WS_BORDER 說明 特性參數
Window Styles  建立一個可重疊的視窗。 WS_OVERLAPPED 建立一個具有下列特性的視窗: WS_OVERLAPPED 、 WS_CAPTION 、 WS_SYSMENU 、 WS_THICKFRAME 、 WS_MINIMIZEBOX 、 WS_MAXIMIZEBOX 。 WS_OVERLAPPEDWINDOW 建立一個有最小化按鈕的視窗 ( 須與 WS_SYSMENU 並用 ) 。 WS_MINIMIZEBOX 建立一個彈出式視窗 ( 不可與 WS_CHILD 並用 ) 。 WS_POPUP 建立一個起始大小為最小化的視窗。 WS_MINIMIZE 建立一個有最大化按鈕的視窗 ( 須與 WS_SYSMENU 並用 ) 。 WS_MAXIMIZEBOX 建立一個起始大小為最大化的視窗。 WS_MAXIMIZE 建立一個具有水平捲軸的視窗。 WS_HSCROLL 說明 特性參數
Window Styles  建立一個具有垂直捲軸的視窗。 WS_VSCROLL 設定視窗一開始即顯示在螢幕上。 WS_VISIBLE 建立一個可用滑鼠調整大小的細外框視窗。 WS_THICKFRAME 設定使用者可以利用 Tab 鍵在視窗的控制項中移動。 WS_TABSTOP 建立一個左上角可拉出系統選單的視窗。 WS_SYSMENU 建立一個彈出式視窗並具有 WS_BORDER 、 WS_POPUP 、 WS_SYSMENU 等特性。 WS_POPUPWINDOW 說明 特性參數
因此若不想要視窗右上角的極大極小鈕,就得這麼做: Create(NULL, &quot;Hello MFC&quot;, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, rectDefault, NULL, &quot;MainMenu&quot;); 若希望視窗有垂直捲軸,可在第三個參數上增加 WS_VSCROLL 。 除了上述標準的視窗風格,另有所謂的擴充風格,可以在 Create 的第七個參數 dwExStyle 指定之。擴充風格唯有以 ::CreateWindowEx( 而非 ::CreateWindow) 函式才能完成。事實上, CFrameWnd::Create  最終呼叫的正是  ::CreateWindowEx 。 建立視窗框架的函數
練習二 請更改程式具有最大化按鈕的視窗 ( 可最大化,但最小化 disable) 。且有水平以及垂直捲軸。
Create  的第四個參數 rect 指定視窗的位置與大小。預設值 rectDefault 是 CFrameWnd 的一個  static  成員變數,告訴  Windows  以預設方式指定視窗位置與大小,就好像在 SDK  程式中以  CW_USEDEFAULT  指定給  CreateWindow  函式一樣。如果你很有主見,希望視窗在特定位置有特定大小,可以這麼做: Create(NULL,&quot;Hello MFC&quot;,WS_OVERLAPPEDWINDOW, CRect(40, 60, 240, 460),NULL,&quot;MainMenu&quot;); 建立視窗框架的函數
練習三 請更改程式位置為 (40,60) ,寬  400 ,高  400 。
第五個參數 pParentWnd 指定父視窗。對於一個 top-level 視窗而言,此值應為 NULL ,表示沒有父視窗 ( 其實是有的,父視窗就是  desktop  視窗 ) 。 第六個參數 lpszMenuName 指定一個定義在資源檔 (RC 檔 ) 的選單名稱。 第八個參數 pContext 是一個指向 CCreateContext 結構的指標, framework 利用它,在具備 Document/View 架構的程式中初始化外框視窗。本例不具備 Document/View 架構,所以不必指定 pContext 參數,預設值為 NULL 。 建立視窗框架的函數
建立視窗框架的函數 擴充風格 ( 第七個參數 dwExStyle)  : 設定視窗接受檔案以拖拽方式開啟。 WS_EX_ACCEPTFILES 讓視窗有向左對齊的屬性,此為預設值。 WS_EX_LEFT 建立一個雙外框且具有標題欄的視窗。 WS_EX_DLGMODALFRAME 允許使用者使用 Tab 鍵操作子視窗。 WS_EX_CONTROLPARENT 建立一個在標題欄具有問號按鈕的視窗,當使用者點擊該問號時,視窗將會收到 WM_HELP 訊息。 WS_EX_CONTEXTHELP 建立具有 3D 立體感的視窗 ( 帶陰影的邊界 ) 。 WS_EX_CLIENTEDGE 說明 參數
建立視窗框架的函數 =WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE WS_EX_OVERLAPPEDWINDOW =WS_EX_WINDOWEDGE | WS_EX_TOPMOST WS_EX_PALETTEWINDOW 在視窗的客戶區左方效置一個捲軸。 WS_EX_LEFTSCROLLBAR 在視窗的客戶區左方效置一個捲軸,此為預設值。  WS_EX_RIGHTSCROLLBAR 讓視窗具有向右對齊的特性。 WS_EX_RIGHT 設定子視窗不必於被建立或消減時傳出 WM_PARENTNOTIFY 訊息給父視窗。 WS_EX_NOPATARENTNOTIFY 建立一個多文件的子視窗。 WS_EX_MDICHILD 以左向右的方式顯示視窗文字,預設值。 WS_EX_LTRREADING 說明 參數
建立視窗框架的函數 建立一個透明視窗。 WS_EX_TRANSPARENT 以右向左的方式顯示視窗文字, WS_EX_RTLREADING 建立一個具有浮雕外框的視窗。 WS_EX_WINDOWEDGE 設定視窗置於所有不具 WS_EX_TOPMOST 特性視窗之上,即使該視窗並不處於有效狀態。 WS_EX_TOPMOST 建立一個工具視窗,該視窗被當成一個浮動的工具列使用。 WS_EX_TOOLWINDOW 建立一個 3D 外框的視窗,且不接受使用者之資料輸入。 WS_EX_STATICEDGE 說明 參數
練習四 請更改程式成為一個 可接受檔案 且 顯示於最上層 的視窗 ( 試著切換到不同視窗及拖曳檔案到這個視窗看畫面的變化 ) 。
BOOL CWnd::ShowWindow(int nCmdShow) 顯示視窗框架的函數 以最小化方式顯示視窗。 SW_SHOWMINIMIZED 將視窗最小化,縮成一個 icon 。 SW_SHOWMINNOACTIVE 以最大化方式顯示視窗。 SW_SHOWMAXIMIZED 隱藏視窗,並將控制權交給其視窗。 SW_HIDE 以設計大小,顯示視窗。 SW_SHOW 顯示窗,如果視窗處於最大化或者最小化,則還原到預設的大小。 SW_RESTORE 將視窗最小化,並將控制權交給目前作業系統中最上層的視窗。 SW_MINIMIZE 說明 參數
顯示視窗框架的函數 以目前的狀態顯示視窗。 SW_SHOWNA 顯示視窗,並將其設定為活動視窗,如果視窗為最小化或最大化,則還原至預設的位置與大小。 SW_SHOWNORMAL 以上一次顯示的大小與位置顯示視窗。 SW_SHOWNOACTIVE 說明 參數
建立自訂視窗程式 自訂視窗框架物件 自訂視窗框架與資源檔的建立 選單的操作
自訂視窗框架物件 剛剛我們僅簡單地介紹如何使用 CFrameWnd 類別產生一個空白的視窗框架,與您平時所看到具有選單、工具列… . 等視窗元件的視窗介面相差甚遠。 當想要建立一個自訂的視窗框架時,必須建立一個繼承於 CFrameWnd 類別的視窗框架類別,然後將視窗元件 組合 出自訂的視窗類別。
接下來的程式範例裡,將建立一個類別,並利用資源檔建立一個選單。而整個應用程式,其架構與 HelloMFC 並沒有不同,只是由於我們希望能自訂視窗框架,因此,不直接利用 CFrameWnd 類別,而使用 繼承 的方式,由 CFrameWnd 類別衍生出 自訂 的 MyFrame 類別,以便修改出欲希望建立的視窗框架類別。 自訂視窗框架物件
下圖是應用程式的架構。 自訂視窗框架物件
我們將利用 test 專案介紹下列重點: 視窗框架與資源檔 視窗元件的使用 以下是程式執行畫面:  自訂視窗框架物件
自訂視窗框架物件:選擇專案類型
自訂視窗框架物件:建立空白專案
自訂視窗框架物件:準備加入資源
自訂視窗框架物件:建立資源檔
自訂視窗框架物件:新增資源 按下右鍵後,請點選「 Insert 」
自訂視窗框架物件:建立 Menu
自訂視窗框架物件:建立選單項目
自訂視窗框架物件:建立選單項目 2
自訂視窗框架物件:設定標頭檔 按下右鍵後,請點選「 Resource Includes… 」
自訂視窗框架物件:建立標頭檔
自訂視窗框架物件: .h 檔加入專案 在 Header Files 按下右鍵選擇「 Add Files to Folder 」 ,就可將剛剛設定的 resource.h 加入專案內
Menu Item  屬性 ID:  按下  menu item  傳回的  command  代號 Caption: menu item  的文字  (&quot;&&quot; :  快速鍵 ) Seperator:  分隔線 Checked: menu item  是否被選取 Pop-up: menu &quot;folder&quot; or menu item Grayed:  是否為  enabled Inactive:  是否正為游標選取中 Menu 屬性
MyFrame Template Method Design Pattern CWinApp MyApp CFrameWnd MyFrameWindow MyFrame
自訂視窗框架與資源檔的建立 在 MyFrame 程式範例裡,雖然是以自訂的類別建立視窗框架物件,但 MyFrame 程式架構與 HelloMFC 程式範例其實是一樣的。二者在程式碼中較不同的部份在於建立視窗框架的時機,在 HelloMFC 裡是在 MyApp:InitInstance 函數裡建立,而 MyFrame 程式範例則是將 CFrameWnd::Create 函數改到 MyFrameWindow 類別的建構子中執行,不過,不論執行於 MyApp::IninInstance 函數或 MyFrameWindow 類別的建構子,其實是一樣的。 此外, MyFrameWindow 類別的建構子除執行 CFrameWnd::Create 建立視窗外,尚建立了視窗所使用的功能表。
自訂視窗框架與資源檔的建立 視窗框架類別是負責產生應用程式物件所使用的視窗框架物件,也就是應用程式的視窗介面。 資源檔內定義的資源大部份都是建立視窗框架時所用的元件。在 Visual C++ 所提供的整合開發環境裡,資源的建立可以藉由資源編輯器的協助來完成,並且自動產生定義資源代號的標頭檔。在本例中為 resource.h 標頭檔。
在程式範例的第 2 行裡,載入的 resource.h 便是由資源編輯器自動產生之標頭檔,該檔由資源檔( MyFrame.rc )所使用。 #include “resource.h“  // 由資源編輯器所產生的標頭檔 在 resource.h 中,將定義選單資源的代碼,如:代表選單的 IDR_MENU1 ,以及選單選項的 ID_Exit 。 自訂視窗框架與資源檔的建立
自訂視窗框架與資源檔的建立
Resource Script Accelerator Bitmap Cursor Dialog Icon Menu String Table Toolbar Version 自訂視窗框架與資源檔的建立
選單的操作  在程式中欲操作資源檔的資源物件時,第一件事就是要在程式裡建立一個相對應的物件,以該物件代表資源檔的資源,當在程式中,欲操作資源檔的資源時,便可透過該物件達到目的。
選單的操作  所以,當在資源檔完成選單的建立後,若欲將選單加入視窗框架時,必須先在程式裡建立一個相對應於選單資源的物件。 因此,在 MyFrameWindow 類別的建構子裡,將建立一個 CMenu 選單物件,並以 CMenu::LoadMenu 為該物件載入選單資源。  FMenu = new CMenu; // 產生選單 FMenu->LoadMenu(IDR_MENU1);  // 載入選單 , 再利用 CWnd::SetMenu 函數將選單物件設定給視窗框架物件。 SetMenu(FMenu); // 設定視窗所使用的選單
BOOL CMenu::LoadMenu(LPCTSTR lpszResourceName) BOOL CMenu::LoadMenu(UINT nIDResource) 函數說明 該函數有二種形式,一為傳入選單資源名稱,另一為傳入選單識別子,該函數如果成功載入選單資源,將傳回非零,失敗則傳回零值。 參數說明 LPCTSTR lpszResourceName :  選單名稱 UINT nIDResource :  選單的識別子。 選單的操作
BOOL CMenu::SetMenu(CMenu *pMenu) 函數說明 設定目前的視窗框架所使用的選單。 參數說明 CMenu *pMenu :  選單物件指標,指向視窗框架所欲使用的選單物件。 選單的操作
視窗訊息處理 視窗訊息的傳遞與處理 訊息映射表與回應函數的建立 利用滑鼠繪圖 訊息方塊的使用與視窗的破壞 鍵盤訊息處理
視窗訊息的傳遞與處理 前面說明了視窗程式的執行方式,是以 回應訊息 為基礎。 在視窗作業系統下,作業系統將不斷由電腦系統的周邊裝置得到訊息,就連您輕輕地移動了一下滑鼠,作業系統也會收到滑鼠移動的訊息。
訊息的用途 外在環境發生的事件 , 透過訊息通知應用程式 應用程式之間可藉由訊息互相溝通 事件發生 ,Window 傳訊息給應用程式 , 應用程式可以針對訊息做適當的回應 應用程式送訊息給自己 , 避免程式碼重複 不可奪取式的多工跟可奪取式的多工 視窗訊息的傳遞與處理
訊息的用途 外在環境發生的事件 , 透過訊息通知應用程式 應用程式之間可藉由訊息互相溝通 事件發生 ,Window 傳訊息給應用程式 , 應用程式可以針對訊息做適當的回應 應用程式送訊息給自己 , 避免程式碼重複 視窗訊息的傳遞與處理
視窗訊息的傳遞與處理 並不是所有的訊息都必須回應,比如:您很無聊地在作業系統的桌面上隨意移動滑鼠,這種訊息系統就沒必要理會。 在這樣多而繁雜的訊息中,如何讓應用程式知道究竟哪些訊息需要回應?以及該如何回應呢?這可要透過訊息映射表的建立。
利用 MFC 撰寫視窗程式時,應用程式回應訊息的機制是靠建立訊息映射表來完成的。首先,可在負責回應訊息的類別裡,加入訊息映射表的宣告。 DECLARE_MESSAGE_MAP() // 宣告訊息映射表 然後,在該類別外宣告所處理的訊息,以及訊息處理函數。 BEGIN_MESSAGE_MAP ( 類別名稱  ,  基礎類別名稱 ) 訊息回應項目 … END_MESSAGE_MAP () 視窗訊息的傳遞與處理
在說明如何定義訊息回應方式前,我們先說明回應訊息與處理函數的種類,共分為二種: 標準系統訊息:標準系統訊息是由作業系統所產生的訊息,比如:滑鼠左鍵被按下或者移動滑鼠…等。 命令訊息:命令訊息是指由使用者自行定義的選單、工具列、控制項…等視窗元件,被選取時產生的訊息。 視窗訊息的傳遞與處理
標準系統訊息是由作業系統所產生的訊息,比如:滑鼠左鍵被按下或者移動滑鼠…等。而接收並處理這類標準系統訊息的類別,必須衍生自 CWnd 類別。這類訊息的回應項目定義方式通常以 ON_WM_XXX 方式定義,例如欲回應滑鼠移動時產生的訊息時,其訊息回應項目的定義方式如下: BEGIN_MESSAGE_MAP (…, …)   ON_WM_MOUSEMOVE()   … END_MESSAGE_MAP () 標準系統訊息
標準系統訊息 對於回應某一系統訊息的函數名稱, MFC 均已定義,比如:回應滑鼠移動訊息的函數為 MFC 預設之 OnMouseMove ;而宣告該函數時,其宣告方式如下: afx_msg  void  類別名稱 ::OnMouseMove(UINT nFlags, CPoint point) { // 如果宣告在類別內,不須宣告類別名稱 … // 回應敘述 } 其中 nFlags 與 point 為傳入回應函數的參數,詳細的說明請看後面的介紹。
基本的滑鼠訊息類型 捲動滾輪 OnMouseWheel WM_MOUSEWHEEL 滑鼠移動 OnMouseMove WM_MOUSEMOVE 鬆開滑鼠右鍵 OnRButtonUp WM_RBUTTONUP 按下滑鼠右鍵 OnRButtonDown WM_RBUTTONDOWN 雙按滑鼠右鍵 OnRButtonDblClk WM_RBUTTONDBCLK 鬆開滑鼠左鍵 OnLButtonUp WM_LBUTTONUP 按下滑鼠左鍵 OnLButtonDown WM_LBUTTONDOWN 雙按滑鼠左鍵 OnLButtonDblClk WM_LBUTTONDBCLK 說明 處理函式 滑鼠訊息
命令訊息 命令訊息是指由使用者自行定義的選單、工具列、控制項…等視窗元件,被選取時產生的訊息。回應這類訊息的類別必須衍生自 CCmdTarget 類別。這類訊息回應項目的定義方式如下: BEGIN_MESSAGE_MAP (…, …)   ON_COMMAND( 訊息代號  ,  回應函數 )   … END_MESSAGE_MAP ()
命令訊息 與標準系統訊息不同的是,命令訊息必須在建立該命令時,即建立一個代號,比如:定義 File 選單的 Exit 選項為 ID_EXIT1 。回應函數的名稱則必須由我們定義,比如:回應 File 選單的 Exit 選項的函數名稱為 OnExit 。宣告這類訊息處理函數時,必須在該函數前加上 afx_msg 。下面是宣告訊息處理函數的語法。 afx_msg  void  回應函數名稱 (  參數… )
宣告處理 ID_EXIT1 訊息的 OnExit 函數的語法如下: afx_msg  void  OnExit( )  { … } 對於大部份視窗程式常使用到的命令, MFC 亦定義了標準命令代號( Standard Command IDs ),並且完成了相對應的回應函數,例如:關閉視窗、關閉應用程式…等。 因此,當您使用了 MFC 已定義的命令訊息,可以不必重新定義回應函數,也不必宣告回應該訊息的函數。 命令訊息
訊息映射表的建立 下面以建立 MyFrame 類別的訊息映射表為例,說明訊息映射表的建立。 class MyFrame : public CFrameWnd  { … DECLARE_MESSAGE_MAP()  // 宣告 MyFrame 類別擁有一個訊息映射表 }; BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)  // 宣告訊息映射表回應的訊息與處理函數 ON_COMMAND(ID_Exit1, OnExit) ON_WM_LBUTTONDOWN() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() END_MESSAGE_MAP() 命令訊息 標準系統訊息
建立訊息映射表與裝置內文的程式 練習增加回應訊息的部份。 Message 範例 1 :滑鼠傳出的標準系統訊息處理及裝置內文物件 (Device Context) 的應用。 Message 範例 2 :在這個範例裡,回應了兩種訊息,一是由滑鼠傳出的標準系統訊息,另一是由選單傳出的命令訊息。
Message 範例 1 請依照講義建立 C++ 檔案
在這個範例裡,回應了兩種訊息,一是由滑鼠傳出的標準系統訊息,另一是由選單傳出的命令訊息。 回應滑鼠訊息時,將會在視窗中繪出滑鼠移動的軌跡。命令訊息的部份,則示範如何關閉視窗。因此,本程式的重點如下: 訊息映射表與回應函數的建立 利用滑鼠繪圖 訊息方塊的使用與視窗的破壞 Message 範例 2
Menu resource 設定 Message 範例 2
訊息映射表與回應函數的建立 在 MyFrame 類別的定義裡, 宣告了該類別擁有訊息映射表 ,並在類別 定義外,建立 MyFrame 類別所接受訊息的映射表 ( 以 Message 範例 2 說明 ) class MyFrame : public CFrameWnd { …   DECLARE_MESSAGE_MAP()  // 宣告訊息映射表 }; BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)  // 建立 MyFrame 類別的訊息映射表   ON_COMMAND(ID_Exit1, OnExit)  // 回應 ID_EXIT1 訊息   ON_WM_LBUTTONDOWN() // 回應滑鼠左鍵被按下   ON_WM_MOUSEMOVE() // 回應滑鼠游標移動   ON_WM_LBUTTONUP() // 回應滑鼠左鍵被放開 END_MESSAGE_MAP()
對於滑鼠訊息及關閉視窗訊息的回應,將利用 MyFrame 類別回應。 下面程式片段是 Message 範例 2 中的回應函數。 class MyFrame : public CFrameWnd {  … afx_msg void OnExit()  //ID_EXIT1 的回應函數 { … } afx_msg void OnLButtonDown(UINT nFlags, CPoint point) { SetCapture(); }  // 滑鼠左鍵按下的回應函數,取得滑鼠訊息接收權 afx_msg void OnMouseMove(UINT nFlags, CPoint point) { … }   afx_msg void OnLButtonUp(UINT nFlags, CPoint point)   { ReleaseCapture(); } // 滑鼠左鍵放開的回應函數,釋放滑鼠訊息接收權 DECLARE_MESSAGE_MAP() // 宣告訊息映射表 }; 訊息映射表與回應函數的建立
滑鼠訊息傳入的參數 當滑鼠訊息產生時,該訊息會一併把滑鼠產生此訊息時,幾個特殊按鍵狀態,利用 nFlags 傳入,而滑鼠游標的座標,則經由 point 參數傳入。 下表是 nFlags 參數傳入旗標的意義。 訊息映射表與回應函數的建立 滑鼠的左邊按鍵被按下 MK_LBUTTON 鍵盤上的 SHIFT 鍵被按下 MK_SHIFT 滑鼠的右邊按鍵被按下 MK_RBUTTON 滑鼠的中間按鍵被按下 MK_MBUTTON 鍵盤上的 CTRL 鍵被按下 MK_CONTROL 說明 旗標
預設的命令訊息 在訊息映射表中,並未看到回應 File 選單中 Exit 選項的項目。可是當點選該選項時,視窗卻一樣會關閉。這是因為 MFC 已經為 ID_APP_EXIT 預設了回應函數。而 ID_APP_EXIT 就是提到的 MFC 所預設的標準命令代號 (Standard Command IDs) 。 訊息映射表與回應函數的建立

mfc