mfc

11,916 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
11,916
On SlideShare
0
From Embeds
0
Number of Embeds
478
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

mfc

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

×