天天看點

VC++中動态生成菜單技巧

<a href="http://old.vckbase.com/document/viewdoc/images/lyh/DynamicMenu.zip">下載下傳源代碼</a>

一.前言

    在實際運用中,經常需要根據操作來增減菜單和菜單項。在VC++開發環境下,動态生成菜單的方法有多種。例如:可以利用資源編輯器建立菜單資源,然後在程式運作中動态加入菜單,這種動态生成菜單的方法比較常見,運用比較多。用這種方法動态增加菜單時,首先需要在Resource.h中添加菜單ID;由于是動态生成的菜單選項,是以要實作它的功能就不能在ClassWizard中映射函數了,需要在頭檔案中手動添加消息函數原型,在代碼檔案中手動添加消息映射和添加消息響應函數。動态生成菜單的另一種方法,不能事先對每個菜單ID進行定義,比如從資料庫中讀出的每條記錄内容動态添加為菜單項,菜單項的數量不是固定的,可以在動态添加菜單項時使菜單項的ID順序遞增;對菜單項的消息響應不能事先寫出響應代碼,而需要根據菜單ID動态響應函數。

二.菜單相關知識

2.1 常用菜單操作函數

文中涉及到的VC++中常見的菜單隻要操作如下:

GetMenu() - 獲得與架構視窗相連結的菜單。

InsertMenu() – 在指定位置插入新的菜單項,其他的選項向下移。

GetSubMenu() – 獲得子菜單指針。

GetMenuItemCount() – 得到菜單下的菜單項的個數。

AppendMenu() – 添加一個新菜單。

GetMenuString() – 獲得指定菜單項的标記。

DeleteMenu() – 删除菜單。

2.2 菜單消息處理

    Windows消息分為3類:标準Windows消息、指令消息、控件通知消息。标準消息指除WM_COMMAND之外,是以以WM_字首開始的消息,包括鍵盤消息和視窗消息等;指令消息,指來自菜單、快捷鍵、工具欄按鈕等使用者界面對象發出的WM_COMMAND消息。其中,在MFC中,通過菜單項的辨別(ID)來區分不同的指令消息;在SDK中,通過消息的wParam參數識别。控件通知消息,是對控件操作而引起的消息,是控件和子視窗向其父視窗發出的WM_COMMAND通知消息。

菜單指令則屬于指令消息,一個菜單指令可以映射到架構類、視圖類或文檔類的某一個成員函數,但不能同時映射到多個成員函數上。即使将一個菜單指令同時映射到多個不同的成員函數上,同時隻有一個成員的映射是有效的。在MFC文檔/視圖結構中映射有效的優先級高低順序為視圖類、文檔類、架構類。

菜單消息一旦在其中一個類中響應則不再在其他類中查找響應函數。

具體來說,菜單指令消息路由過程是這樣的:當點選一個菜單項的時候,最先接受到菜單項消息的是CMainFrame架構類,CMainFrame架構類将會把菜單項消息交給它的子視窗View類,由View類首先進行處理;如果View類檢測到沒對該菜單項消息做響應,則View類把菜單項消息交由文檔類Doc類進行處理;如果Doc類檢測到Doc類中也沒對該菜單項消息做響應,則Doc類又把該菜單項消息交還給View類,由View類再交還給CMainFrame類處理。如果CMainFrame類檢視到CMainFrame類中也沒對該消息做響應,則最終交給App類進行處理。而且一個消息一旦在某個類中被響應過,則不再接着傳遞。

三.程式設計執行個體

3.1 菜單執行個體工程

(1)建立工程

    VC++中建立工程DynamicMenu:第一步選擇“單文檔“,接下來幾步不用修改使用預設設定,到最後一步将Base class下拉菜單選”CFormView“,即建立基于FormView的MFC運用程式。本項目中3.3節以動态建立控件為例,而視圖中FormView可以放置控件,是以選FormView。

(2)建立菜單資源

    在Resource中Menu下的菜單中,添加菜單“動态菜單示例“,下設兩個菜單項,分别是”添加例一菜單““添加例二菜單”如圖1所示。ID分别為ID_FIRSTMENU和ID_SECMENU。點選這兩個菜單項,通過兩種方式動态添加兩個菜單。僅添加了菜單,并沒有實作菜單的功能,即沒有對應的指令處理函數與菜單項對應,是以,添加的菜單項是灰色的,即為目前不可用狀态。添加新菜單項後,還應該為新的菜單項指定一個消息響應函數。

VC++中動态生成菜單技巧

                                                圖一     建立兩個菜單項

    通過MFC ClassWizard在View下為兩菜單項添加消息響應函數,ID_FIRSTMENU的響應函數為void  CDynamicMenuView::OnFirstMenu(),ID_SECMENU的響應函數為void CDynamicMenuView::OnSecmenu()。

3.2 動态添加菜單

    本例适用于菜單項名稱、數量事先固定,僅在需要時将事先定義好的菜單動态添加到主菜單中,不需要時删除即可。響應函數需要通過手動添加的,更改菜單項時需要重新修改代碼。

本例功能:通過點選上述DynamicMenu工程中的菜單“動态菜單示例”下的“添加例一菜單”,添加新的動态菜單“動态菜單一“,點選其下的菜單項”First1“即進行菜單響應,彈出提示框,菜單項”First2“未定義消息響應則不可,如圖2所示。

VC++中動态生成菜單技巧

                                                 圖2     運作界面

主要程式設計步驟:建立菜單資源,手動加入菜單ID、消息映射、消息響應函數。

實作步驟:

(1)在以上DynamicMenu工程中的Resource.h中添加要生成的菜單ID,如:

(2)在MainFrm.h中手動添加指令響應函數原型。

(3)手動添加消息映射,在MainFrm.cpp用ON_COMMAND宏關聯消息響應函數

(4)新增菜單,添加的菜單項往往是灰色的,不可用,隻有為此菜單項定義有相信的響應函數才會可用。為ID_FIRST1菜單項定義了消息響應函數,則菜單項為可用。沒有為ID_FIRST2定義消息響應函數,則定義的菜單色為灰色。在MainFrm.cpp中手動編寫消息響應函數如下:

(5)點選”動态菜單示例“下的”添加例一菜單“時,在菜單末尾添加”動态菜單一“。

通過MFC ClassWizard在CDynamicMenuView下為菜單項ID_FIRSTMENU添加消息響應函數如下:

3.3 将資料庫中讀出的記錄動态添加為菜單項

    本列适用于菜單項數量和菜單項顯示名稱事先不固定的場合,這需将菜單項寫入資料庫,對資料庫内容進行更新維護即可。在需要時讀取資料庫中記錄,動态添加為菜單項。

本列功能:通過點選上述DynamicMenu工程中的菜單“動态菜單示例“下的”添加例二菜單“,即在菜單末尾添加新的動态菜單”動态菜單二“,其中的菜單項由資料庫中讀出記錄内容添加而成,點選各菜單項即進行菜單響應,如圖3.

VC++中動态生成菜單技巧

                                                圖三    運作界面

    點選新添加的菜單項,根據菜單項的名稱和目前資料庫中的記錄内容,動态建立控件。如菜單項名為“文本框“,資料庫中目前記錄中類型字段contype為”文本“,當點選該菜單項時在程式運作界面中動态建立一文本框。如為”下拉框“,資料庫中目前記錄中類型字段contype為”選擇“,點選該菜單項時在程式運作界面中動态建立一下拉框。

程式設計步驟:建立資料庫,其中的記錄即為菜單二的菜單項;動态添加菜單項時使菜單項的ID順序遞增;菜單項資料量不固定,對每個菜單項的消息響應也不能事先寫出響應代碼,需要動态響應函數,是以根據菜單ID并結合資料庫記錄内容在菜單項響應函數中進行功能分類并響應。

(1)建立Access資料庫menu,表名dynamicmenu,表中設兩個字段分别是myname、contype,字段類型均為“文本“。表中添加兩條記錄:文本框,文本;下拉框,選擇,如圖4所示。以下根據contype的值動态建立控件,并将myname值作為控件中顯示内容。

VC++中動态生成菜單技巧

                                                圖4     表結構與資料

(2) 在dynamicmenu工程中連接配接資料庫。

在DynamicMenu.cpp檔案的InitInstance()中添加如下連接配接代碼:

(3)在CDynamicMenuView中設定全局變量flag作為判斷是否添加了“示例菜單二“的标志,并在CDynamicMenuView的構造函數中設定初值為false,代碼如下:

(4)點選菜單項“添加例二菜單“時,從資料庫中讀取記錄,添加為動态菜單項,菜單添加成功後将flag置為true,便于在菜單響應時進行判斷。

通過MFC ClassWizard在CDynamicMenuView下為菜單ID_SECMENU添加消息響應函數如下:

(5)添加菜單項消息響應函數。

    MFC确定一個Command ID 是否有Handler與之對應是通過OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO* pHandlerInfo),然後根據傳回值來确定的。傳回值為true,表示有對應的處理函數;傳回值為false,表示沒有。其中參數nID就是發送過來的消息ID号,對于菜單,就是菜單的ID;參數nCode為0表示是指令消息,如單擊菜單項發出的消息,為-1就表示是UPDATE_COMMAND_UI消息;參數pHandleInfo不為NULL時,表示在檢測;當其為NULL時表示是在路由這個指令消息,希望能得到處理。

重載了CDynamicMenuView的OnCmdMsg()函數,因為要在CDynamicMenuView中處理這些動态添加的菜單項。通過calss wizard,為CDynamicMenuView添加消息響應函數OnCmdMsg,添加代碼如下:

其中Handler(strMenuName)是使用者自定義的菜單項單擊的響應代碼,參數為目前點選的菜單項的名稱,根據菜單項動态建立控件,主要代碼如下:

四.小結

    通過兩個執行個體在VC++6.0中實作動态生成菜單,3.2小節适用于需要添加的菜單項比較固定,需要預先建立菜單項ID,響應函數事先确定并進行手動添加,修改時涉及代碼。3.3小節适用于菜單項數量和菜單項顯示名稱不固定、經常變化的場合,隻需将菜單項寫入資料庫,對資料庫内容進行更新維護,免去了一般菜單資源更改時對應用程式代碼重新編輯的繁瑣。