MFC——5.菜单

Lesson5:菜单

 

菜单是用户交互界面中一个重要的角色,本文主要讲解了菜单的使用方法,包括解析MFC的Frame,App,Doc,View类对菜单的响应顺序,菜单的基本操作和右键弹出菜单。

1.    MFC的类对菜单命令响应顺序

在MFC的资源里面有一个菜单项,可以在这里添加菜单。菜单设置里Pop-up类型的菜单成为弹出式菜单,这种菜单不能响应命令,一般默认顶层菜单都是弹出式菜单,它们会有子菜单,子菜单可以响应命令。当我们添加了菜单按钮并给了标识IDM_TEST后,在向导里的命令里选择与这个ID对应的命令消息,然后编辑代码。这里通过产生消息框进行测试。

void CMenuView::OnTest()

{

         //TODO:  在此添加命令处理程序代码

         AfxMessageBox("ViewClicked!");

}

上面的测试是在View类里的,那么对于同一个菜单,当在MFC的Frame,App,Doc,View类里分别添加函数后,事实上响应的先后顺序是View,Doc,Frame,App。我们看看MFC的消息分类。

 

【消息的分类】

标准消息:除WM_COMMAND之外,所有以WM_开头的消息(窗口重绘的WM_PAINT消息,窗口创建的WM_CREATE,键盘按键WM_CHAR消息等)。从CWnd派生的类,都可以接收到这类消息。

命令消息:来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。

通告消息:由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。从CCmdTarget派生的类,都可以接收到这类消息。

从从CWnd派生的类,可以接收标准消息、命令消息、通告消息。从CCmdTarget派生的类,可以接收命令消息、通告消息。

 

菜单命令消息的路由过程】 当点击菜单项时,框架类首先接收到这个消息,并把消息交给它的子窗口,view类,由视类进行处理。view类首先查看自己是否有成员函数处理此消息,如果能处理,就由调用相应的响应函数来处理,如果没有,由view类交给doc类处理,doc查找自己能否处理,如果能处理,就由调用相应的响应函数来处理,如果没有,就交还给view类,view类又交还给frame类。这时frame类查看自己能否处理此消息,如果能则处理,不能则交给应用App程序类来处理。

 

2.    菜单相关操作

对菜单进行修改是在frame框架类窗口的OnCreate函数里进行的。下面是一系列的菜单操作。

int CMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct)

{

         if(CFrameWnd::OnCreate(lpCreateStruct) == -1)

                   return-1;

 

         if(!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP |CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

                   !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

         {

                   TRACE0("未能创建工具栏\n");

                   return-1;      // 未能创建

         }

         if(!m_wndStatusBar.Create(this))

         {

                   TRACE0("未能创建状态栏\n");

                   return-1;      // 未能创建

         }

         m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT));

 

         //TODO:  如果不需要可停靠工具栏,则删除这三行

         m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

         EnableDocking(CBRS_ALIGN_ANY);

         DockControlBar(&m_wndToolBar);

 

         /*************1.标记菜单*****************/

       GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED);         //逐层次访问子菜单(文件 0)的菜单项(新建 0)

         //GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_CHECKED);  //以命令ID访问

 

 

         /****************        2.创建默认菜单*******************/

         //对于一个菜单的默认菜单,只能有一个,当设置多个的时候就只有一个生效

         GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);    //设置默认的菜单项(表现为加粗)。第一个参数是依赖于第二个参数,如果第二个参数是false,第一个参数用命令的ID,如果第二个参数是true,则第一个参数是位置索引,分割栏也占一个索引

         //GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN,FALSE);   //其中,false是默认的,可以不写

         //GetMenu()->GetSubMenu(0)->SetDefaultItem(5,TRUE);    //设置默认的菜单项时,如果用索引号,注意分栏也占一个号

        

         /*******************3.创建图形标记菜单************/

         CStringstr;      //以下三行是为了获得系统图标的大小,然后调整图标大小,使图标显示适当

         str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK));

         MessageBox(str);          //标记的大小  

        //CBitmap m_bitmap 作为一个成员函数,写在成员变量里,不在这

         m_bitmap.LoadBitmap(IDB_BITMAP1);              //下载一副自己制作的位图

         GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION, &m_bitmap, &m_bitmap);   //将位图设置在菜单项前

 

         /**********************4.禁用菜单******************/

         GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_BYPOSITION|MF_DISABLED|MY_GRAYED);       //(不能用时自动变灰)在设置同时,需要在frame的构造函数中m_bAutoMenuEnable = FALSE;

 

         /*以下是移除一个菜单后加载一个菜单*/

         //SetMenu(NULL);                    //当参数为NULL时,菜单被移除

 

         //CMenumenu;                          //定义一个菜单,如果用一个局部变量menu,可以用SetMenu设置菜单,但后面用要menu.Detach

         //menu.LoadMenuA(IDR_MAINFRAME);            //加载一个菜单

         //SetMenu(&menu);                                                //设置一个菜单   调用setmenu后一定要紧接着用菜单对象的detach将菜单句柄与菜单对象分开

         //menu.Detach();                     //将菜单句柄和c++对象断开,防止窗口重绘时候发生错误,menu对象析构时不会销毁菜单

         return0;

}

 

3.    右键弹出菜单

在资源中增加一个menu,并对菜单的每一个子菜单设置caption 和ID号。

增加鼠标右键点击的消息响应OnRButtonDown。

对子菜单编写命令处理函数,。

void CMenuView::OnRButtonDown(UINT nFlags,CPoint point)

{

         //TODO:  在此添加消息处理程序代码和/或调用默认值

         CMenumenu;                                //定义一个菜单 

         menu.LoadMenu(IDR_MENU1);                  //加载一个菜单资源

         CMenu*pPopup = menu.GetSubMenu(0);        //获取一个子菜单

         ClientToScreen(&point);                    //将客户区坐标转换为屏幕坐标

 

         pPopup->TrackPopupMenu(TPM_LEFTALIGN| TPM_RIGHTBUTTON, point.x, point.y, this);     //显示菜单

         //TrackPopupMenu第一个参数表示菜单显示的位置,第二三参数表示鼠标点击的位置,第四个表示菜单的拥有者,第五个是默认的,指示了一个区域,当点击区域外面时,菜单无效

         //当地四个选项说明拥有者后,菜单的子菜单的拥有者也是它

          CView::OnRButtonDown(nFlags,point);

}

  

### MFC `resource.h` 文件使用说明 #### 一、文件概述 `resource.h` 是 Microsoft Foundation Classes (MFC) 应用程序中的一个重要头文件,用于定义应用程序中所有资源的符号常量。这些符号通常对应于菜单项、对话框、字符串表和其他类型的资源 ID[^1]。 #### 二、常见操作指南 ##### 添加新资源ID 当创建新的用户界面元素(如按钮、菜单条目等),Visual C++ 开发环境会自动在 `resource.h` 中分配唯一的整数值作为该组件的身份标识符(ID)[^4]。然而,在某些情况下,开发者可能需要手动编辑此文件来添加自定义资源或处理特殊情况下的冲突问题。 ##### 解决ID重复现象 由于项目发展过程中可能会引入外部模块或者团队协作时不同成员之间的工作交接等原因造成同一项目的多个版本间存在相同名称但意义不同的资源实体;另外一种情况是在迁移旧版应用至新版框架下工作时也会遇到类似的困扰——即原有的资源编号体系与当前使用的不兼容而导致冲突。对于上述两种情形可以采取如下措施: - **自动化脚本辅助**:编写专门的小型工具软件帮助清理冗余记录并调整顺序使之更加整洁有序[^2]。 - **人工核查修正**:仔细对比分析各个部分之间的差异之处进而做出适当修改直至消除一切潜在风险为止[^3]。 ```cpp // 示例代码片段展示如何遍历整个文件内容并对其中的数据结构实施必要的更改动作 #include <iostream> #include <fstream> #include <string> using namespace std; int main() { ifstream fin("Resource.h"); ofstream fout("new_Resource.h", ios::out); string line; while(getline(fin,line)){ // 对每一行进行判断和处理逻辑... fout << line << endl; } fin.close(); fout.close(); return 0; } ``` #### 三、最佳实践建议 为了保持良好的维护性和扩展性,应该遵循一些良好习惯: - 定期审查并优化现有的命名空间规划; - 尽量利用IDE自带的功能特性减少人为失误概率; - 建立详细的文档记录每次变更的具体原因及其影响范围以便后续查询参考。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值