作者:sanmao
下载源代码
一.前言
在实际运用中,经常需要根据操作来增减菜单和菜单项。在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。点击这两个菜单项,通过两种方式动态添加两个菜单。仅添加了菜单,并没有实现菜单的功能,即没有对应的命令处理函数与菜单项对应,因此,添加的菜单项是灰色的,即为当前不可用状态。添加新菜单项后,还应该为新的菜单项指定一个消息响应函数。
图一 新建两个菜单项
通过MFC ClassWizard在View下为两菜单项添加消息响应函数,ID_FIRSTMENU的响应函数为void CDynamicMenuView::OnFirstMenu(),ID_SECMENU的响应函数为void CDynamicMenuView::OnSecmenu()。
3.2 动态添加菜单
本例适用于菜单项名称、数量事先固定,仅在需要时将事先定义好的菜单动态添加到主菜单中,不需要时删除即可。响应函数需要通过手动添加的,更改菜单项时需要重新修改代码。
本例功能:通过点击上述DynamicMenu工程中的菜单“动态菜单示例”下的“添加例一菜单”,添加新的动态菜单“动态菜单一“,点击其下的菜单项”First1“即进行菜单响应,弹出提示框,菜单项”First2“未定义消息响应则不可,如图2所示。
图2 运行界面
主要编程步骤:建立菜单资源,手动加入菜单ID、消息映射、消息响应函数。
实现步骤:
(1)在以上DynamicMenu工程中的Resource.h中添加要生成的菜单ID,如:
#define ID_FIRST1 32733 //手动加入的菜单ID_FIRST1 #define ID_FIRST2 32734 //手动加入的菜单ID_FIRST2
(2)在MainFrm.h中手动添加命令响应函数原型。
Protected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //NOTE – the ClassWizard will add and remove member functions here. //DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG Afx_msg void OnFIRST1();//手动添加的消息响应函数宏 DECLARE_MESSAGE_MAP()
(3)手动添加消息映射,在MainFrm.cpp用ON_COMMAND宏关联消息响应函数
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) // NOTE - the ClassWizard will add and remove mapping macros here. //DO NOT EDIT what you see in these blocks of generated code ! ON_WM_CREATE() //}}AFX_MSG_MAP ON_COMMAND(ID_FIRST1,OnFIRST1)//手动添加IDM_HELLO到函数OnHello的映 END_MESSAGE_MAP()
(4)新增菜单,添加的菜单项往往是灰色的,不可用,只有为此菜单项定义有相信的响应函数才会可用。为ID_FIRST1菜单项定义了消息响应函数,则菜单项为可用。没有为ID_FIRST2定义消息响应函数,则定义的菜单色为灰色。在MainFrm.cpp中手动编写消息响应函数如下:
void CMainFrame::OnFIRST1() { MessageBox(“动态菜单示例1!”); }
(5)点击”动态菜单示例“下的”添加例一菜单“时,在菜单末尾添加”动态菜单一“。
通过MFC ClassWizard在CDynamicMenuView下为菜单项ID_FIRSTMENU添加消息响应函数如下:
void CDynamicMenuView::OnFirstmenu() { // TODO: Add your command handler code here CMenu menu; menu.CreatePopupMenu(); //创建空菜单 GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"动态菜单一"); //把菜单添加到现有菜单末尾 menu.AppendMenu(MF_STRING|MF_ENABLED,ID_FIRST1,"First1"); menu.AppendMenu(MF_STRING|MF_ENABLED,ID_FIRST2,"First2"); menu.Detach(); GetParent()->DrawMenuBar(); //重绘菜单 }
3.3 将数据库中读出的记录动态添加为菜单项
本列适用于菜单项数量和菜单项显示名称事先不固定的场合,这需将菜单项写入数据库,对数据库内容进行更新维护即可。在需要时读取数据库中记录,动态添加为菜单项。
本列功能:通过点击上述DynamicMenu工程中的菜单“动态菜单示例“下的”添加例二菜单“,即在菜单末尾添加新的动态菜单”动态菜单二“,其中的菜单项由数据库中读出记录内容添加而成,点击各菜单项即进行菜单响应,如图3.
图三 运行界面
点击新添加的菜单项,根据菜单项的名称和当前数据库中的记录内容,动态建立控件。如菜单项名为“文本框“,数据库中当前记录中类型字段contype为”文本“,当点击该菜单项时在程序运行界面中动态建立一文本框。如为”下拉框“,数据库中当前记录中类型字段contype为”选择“,点击该菜单项时在程序运行界面中动态建立一下拉框。
编程步骤:建立数据库,其中的记录即为菜单二的菜单项;动态添加菜单项时使菜单项的ID顺序递增;菜单项数据量不固定,对每个菜单项的消息响应也不能事先写出响应代码,需要动态响应函数,因此根据菜单ID并结合数据库记录内容在菜单项响应函数中进行功能分类并响应。
实现步骤:
(1)建立Access数据库menu,表名dynamicmenu,表中设两个字段分别是myname、contype,字段类型均为“文本“。表中添加两条记录:文本框,文本;下拉框,选择,如图4所示。以下根据contype的值动态建立控件,并将myname值作为控件中显示内容。
图4 表结构与数据
(2) 在dynamicmenu工程中连接数据库。
在DynamicMenu.cpp文件的InitInstance()中添加如下连接代码:
BOOL CDynamicMenuApp::InitInstance() { … m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=menu.mdb","","",adModeUnknown); … }
(3)在CDynamicMenuView中设置全局变量flag作为判断是否添加了“示例菜单二“的标志,并在CDynamicMenuView的构造函数中设置初值为false,代码如下:
CDynamicMenuView::CDynamicMenuView() : CFormView(CDynamicMenuView::IDD) { //{{AFX_DATA_INIT(CDynamicMenuView) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // TODO: add construction code here flag=false; }
(4)点击菜单项“添加例二菜单“时,从数据库中读取记录,添加为动态菜单项,菜单添加成功后将flag置为true,便于在菜单响应时进行判断。
通过MFC ClassWizard在CDynamicMenuView下为菜单ID_SECMENU添加消息响应函数如下:
void CDynamicMenuView::OnSecmenu()//读取数据库中的记录,添加动态菜单项 { CMenu menu; menu.CreatePopupMenu(); //创建空菜单 GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"动态菜单二"); //把菜单添加到现有菜单末尾 int j=8999; _RecordsetPtr m_pRecordset; m_pRecordset.CreateInstance(__uuidof(Recordset)); try { m_pRecordset->Open("SELECT * FROM DynamicMenu",// 查询DemoTable表中所有字段 m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针 adOpenDynamic, adLockOptimistic, adCmdText); } catch(_com_error *e) { AfxMessageBox(e->ErrorMessage()); } if(!m_pRecordset->BOF) m_pRecordset->MoveFirst(); else { AfxMessageBox("没有记录!!"); return; } //读取记录,添加为菜单项 m_pRecordset->MoveFirst(); while(!m_pRecordset->adoEOF) { j=j+1;//菜单项ID递增 _variant_t var; var=m_pRecordset->GetCollect("myname");//读取记录值 CString str=vtos(var); //添加为菜单项 menu.AppendMenu(MF_STRING| MF_ENABLED | MF_CHECKED,j,str); m_pRecordset->MoveNext(); } menu.Detach(); GetParent()->DrawMenuBar(); flag=true;//菜单添加完毕,设置菜单项添加标志,便于在菜单消息响应中判断 }
(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,添加代码如下:
BOOL CDynamicMenuView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { // TODO: Add your specialized code here and/or call the base class if(flag)//判读是否添加“示例菜单二“ { //得到“示例菜单二“的菜单项总个数 int n = GetParent()->GetMenu()->GetSubMenu(6)->GetMenuItemCount() - 1; if (0 == nCode)//判断是否是命令消息 { //判断当前单击的菜单ID是否在动态菜单项的范围之内 if (GetParent()->GetMenu()->GetSubMenu(6)->GetMenuItemID(0) <= nID && nID<=GetParent()->GetMenu()->GetSubMenu(6)->GetMenuItemID(n)) { if (pHandlerInfo==NULL ) { CString strMenuName; //菜单项名 GetParent()->GetMenu()->GetMenuString(nID,strMenuName,MF_STRING);//根据ID得到菜单项名 Handler(strMenuName); } return true; } } } return CFormView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); }
其中Handler(strMenuName)是用户自定义的菜单项单击的响应代码,参数为当前点击的菜单项的名称,根据菜单项动态建立控件,主要代码如下:
void CDynamicMenuView::Handler(CString strMenuName) { _RecordsetPtr m_pSet2; m_pSet2.CreateInstance(__uuidof(Recordset)); CString strsql2="SELECT * FROM DynamicMenu WHERE myname='"; strsql2=strsql2+strMenuName+"'"; if(m_pSet2!=NULL) { if(m_pSet2->State) m_pSet2->Close(); m_pSet2= NULL; } m_pSet2.CreateInstance(__uuidof(Recordset)); try { m_pSet2->Open((_bstr_t)strsql2, // 查询DemoTable表中所有字段 m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针 adOpenDynamic,adLockOptimistic,adCmdText); } catch(_com_error e) { AfxMessageBox("对象数据库操作失败!!"); //return NULL; } if(!m_pSet2->BOF) m_pSet2->MoveFirst(); else { MessageBox(strMenuName); AfxMessageBox("没有符合条件的关联对象记录!!"); //return NULL; } CString ctype=vtos(m_pSet2->GetCollect("contype")); m_pSet2->Close(); if(ctype=="选择") { CDC *pDC=GetDC(); combox= new CComboBox; combox->Create(WS_CHILD|WS_VISIBLE| CBS_DROPDOWN,CRect((260),(80),(330),(100)), this, 1999); combox->SetWindowText(strMenuName); } else if (ctype=="文本") { CDC *pDC=GetDC(); number= new CEdit; number->Create(WS_VISIBLE| WS_CHILD | WS_BORDER , CRect((260),(40),(330),(60)), this, 2000); //number->MoveWindow((30),(80),(70),(20)); //number->ShowWindow(SW_SHOW); number->SetWindowText(strMenuName); } }
四.小结
通过两个实例在VC++6.0中实现动态生成菜单,3.2小节适用于需要添加的菜单项比较固定,需要预先建立菜单项ID,响应函数事先确定并进行手动添加,修改时涉及代码。3.3小节适用于菜单项数量和菜单项显示名称不固定、经常变化的场合,只需将菜单项写入数据库,对数据库内容进行更新维护,免去了一般菜单资源更改时对应用程序代码重新编辑的繁琐。
>> 本文固定链接: http://www.vcgood.com/archives/3580
作者:sanmao
下载源代码
一.前言
在实际运用中,经常需要根据操作来增减菜单和菜单项。在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。点击这两个菜单项,通过两种方式动态添加两个菜单。仅添加了菜单,并没有实现菜单的功能,即没有对应的命令处理函数与菜单项对应,因此,添加的菜单项是灰色的,即为当前不可用状态。添加新菜单项后,还应该为新的菜单项指定一个消息响应函数。
http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage1.png','Image‘);” onmouseover=”this.style.cursor=’hand’” onmouseout=”this.style.cursor=”” src=”http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage1.png” height=”108″ width=”500″ border=”0″ />
图一 新建两个菜单项
通过MFC ClassWizard在View下为两菜单项添加消息响应函数,ID_FIRSTMENU的响应函数为void CDynamicMenuView::OnFirstMenu(),ID_SECMENU的响应函数为void CDynamicMenuView::OnSecmenu()。
3.2 动态添加菜单
本例适用于菜单项名称、数量事先固定,仅在需要时将事先定义好的菜单动态添加到主菜单中,不需要时删除即可。响应函数需要通过手动添加的,更改菜单项时需要重新修改代码。
本例功能:通过点击上述DynamicMenu工程中的菜单“动态菜单示例”下的“添加例一菜单”,添加新的动态菜单“动态菜单一“,点击其下的菜单项”First1“即进行菜单响应,弹出提示框,菜单项”First2“未定义消息响应则不可,如图2所示。
http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage2.png','Image‘);” onmouseover=”this.style.cursor=’hand’” onmouseout=”this.style.cursor=”” src=”http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage2.png” height=”299″ width=”500″ border=”0″ />
图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.
http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage3.png','Image‘);” onmouseover=”this.style.cursor=’hand’” onmouseout=”this.style.cursor=”” src=”http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage3.png” height=”188″ width=”500″ border=”0″ />
图三 运行界面
点击新添加的菜单项,根据菜单项的名称和当前数据库中的记录内容,动态建立控件。如菜单项名为“文本框“,数据库中当前记录中类型字段contype为”文本“,当点击该菜单项时在程序运行界面中动态建立一文本框。如为”下拉框“,数据库中当前记录中类型字段contype为”选择“,点击该菜单项时在程序运行界面中动态建立一下拉框。
编程步骤:建立数据库,其中的记录即为菜单二的菜单项;动态添加菜单项时使菜单项的ID顺序递增;菜单项数据量不固定,对每个菜单项的消息响应也不能事先写出响应代码,需要动态响应函数,因此根据菜单ID并结合数据库记录内容在菜单项响应函数中进行功能分类并响应。
实现步骤:
(1)建立Access数据库menu,表名dynamicmenu,表中设两个字段分别是myname、contype,字段类型均为“文本“。表中添加两条记录:文本框,文本;下拉框,选择,如图4所示。以下根据contype的值动态建立控件,并将myname值作为控件中显示内容。
http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage4.png','Image‘);” onmouseover=”this.style.cursor=’hand’” onmouseout=”this.style.cursor=”” src=”http://www.vckbase.com/document/viewdoc/images/lyh/exmenuimage4.png” height=”113″ width=”418″ border=”0″ />
图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小节适用于菜单项数量和菜单项显示名称不固定、经常变化的场合,只需将菜单项写入数据库,对数据库内容进行更新维护,免去了一般菜单资源更改时对应用程序代码重新编辑的繁琐。