您的位置:首页 > 编程语言

Windows-菜单编程基本技术

2016-05-06 22:56 281 查看
Windows-菜单编程基本技术

一,简介

在许多的框架中都免不了对菜单进行操作,不管是QT,Android还是IOS,基本的应用程序框架都会涉及到对菜单的API的调用,但是万变不其宗,菜单的基本概念我们清楚之后,我们就能否更好的理解和调用,MFC中对菜单的基本操作相对简单,其中有点复杂的也就算自己实现菜单的命令响应函数的步骤,这其中涉及到对MFC消息映射机制的运用。

二,MFC菜单的分类

1.弹出式菜单

默认顶层菜单为弹出式菜单,不能响应菜单命令,将菜单应用为弹出式需要勾选Pop-Up属性,如下图。



2.菜单栏,子菜单,菜单项三者的区分



相信大家应该能够看明白吧,这是博主在书中总结出的,绝对正确。

三,MFC菜单命令的路由

基本路线是:View->Doc->Frame->App

具体过程分析:当我们点击某个菜单项的时候,最先接受的是Frame类。Frame类将接收的消息交给子窗口View类,View类首先处理。View类根据消息映射机制判断自身是否对此消息相应,响应就处理,消息路由结束。不响应就交给Doc类,Doc类同样判断自身是否对该消息进行响应,响应就处理,不响应就将此消息还给View类,View类再将此消息交给Frame类,Frame再判断自己是否对这个命令消息进行响应,响应就处理,不响应就再交给App类处理。

四,Windows消息分类

1.标准消息

除了WM_COMMAND之外,所有以WM_开头的都是标准消息。

2.命令消息

来自菜单,加速键或者工具栏的按钮的消息,这类消息都以WM_COMMAND形式呈现,通过ID来区分不同的命令。

3.通告消息

控件产生的消息,例如按钮的单击等,目的是为了向其父窗口通知事件的发生,这类消息也是以WM_COMMAND形式呈现。

从CWnd派生的类,三种消息都可以接收。

从CCmdTarget派生的类,不能接收标准消息。

五,基本菜单操作

1.注意:分隔栏也是一个菜单项,必须注意。

2.标记菜单

图片:



创建代码:

#if 0
//通过索引设置标记菜单
GetMenu()->GetSubMenu(0)->CheckMenuItem(0, MF_BYPOSITION | MF_CHECKED);
/*许多的菜单函数的第一个参数的取值由第二个参数来确定*/
#endif

#if 0
//通过ID来设置标记菜单
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW, MF_BYCOMMAND | MF_CHECKED);
#endif


3.默认菜单项(以粗体显示的菜单项)

注意:一个子菜单分支只能有一个默认菜单项

图片:



创建代码:

#if 0
//通过索引设置默认的菜单项
GetMenu()->GetSubMenu(0)->SetDefaultItem(1, TRUE);
#endif

#if 0
//通过ID设置默认的菜单项
GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN, FALSE);
#endif

#if 0
//设置分隔线后面一个菜单项打印为默认菜单项,分割线也算一个菜单项,所以打印的索引是4(分割线) + 1 = 5
GetMenu()->GetSubMenu(0)->SetDefaultItem(5, TRUE);
#endif


4.图形标记菜单

简介:就是菜单项前面有一个相对应的图形标记。

图片:



一定要注意设置的位图的尺寸要跟系统规定的尺寸差不多,可以利用GetSystemMetrics函数

#if 1
//设置图形标记菜单
CString str;

/*
//x = 15 y = 15所以默认的图形标记菜单的位图大小为15 * 15
str.Format(_T("x = %d, y = %d"), GetSystemMetrics(SM_CXMENUCHECK),   GetSystemMetrics(SM_CYMENUCHECK));
MessageBox(str);
*/

//设置图形标记菜单
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bitmap, &m_bitmap);
#endif


5.禁用菜单项

注意:区分禁用变灰,一般来说禁用一个菜单项都会让这个菜单项变为灰色。

另外,为了禁用菜单项,必须取消MFC的默认命令更新机制,在CMainFrame的构造函数中设置:m_bAutoMenuEnable = FALSE;即可

创建代码:

#if 0
//通过索引禁用菜单项
GetMenu()->GetSubMenu(0)->EnableMenuItem(1, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);

#endif

#if 0
//通过ID禁用菜单项
GetMenu()->GetSubMenu(0)->EnableMenuItem(ID_FILE_OPEN, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
#endif


6.移除菜单栏

在MFC的框架类中可以设置不显示菜单栏这个对象。

设置的代码

#if 0
//移除菜单
SetMenu(nullptr);
#endif


7.创建菜单栏对象

MFC也给我们提供了创建菜单栏对象的方法

创建代码:

#if 0
//创建菜单
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
//分离菜单句柄与菜单对象,防止局部变量出错
menu.Detach();
#endif


8.快捷菜单(上下文菜单)

简介:就是我们再程序中右键弹出的菜单项



创建分为3个步骤

第一步:增加菜单资源,设置ID



第二步:为需要响应鼠标右键消息的类添加WM_RBUTTONDOWN消息



第三步:为菜单资源的菜单项设置响应函数



9.动态菜单操作

前面介绍的都是菜单的静态操作,这里介绍下菜单的动态操作。

9**.1菜单栏尾部添加子菜单**

#if 0
//添加弹出式子菜单
CMenu menu;
menu.CreateMenu();
GetMenu()->AppendMenu(MF_POPUP, (UINT_PTR)(menu.m_hMenu), _T("Test2"));
menu.Detach();
#endif


9.2菜单栏中插入子菜单

#if 0
//插入子菜单
CMenu menu;
//先要创建menu对象
menu.CreateMenu();
//插入子菜单
GetMenu()->InsertMenu(2, MF_POPUP | MF_BYPOSITION, (UINT_PTR)(menu.m_hMenu), _T("Test3"));
//因为是局部变量的menu,所以需要分离
menu.Detach();
#endif


9.3根据调用这个函数的对象来删除对应的菜单项

#if 0
//删除索引为1的子菜单
GetMenu()->DeleteMenu(1, MF_BYPOSITION);
#endif

#if 0
//删除第一个子菜单的索引为2的菜单项
GetMenu()->GetSubMenu(0)->DeleteMenu(2, MF_BYPOSITION);
#endif


六,MFC菜单命令更新机制

每一个子菜单下面的菜单项都需要设置自身的状态,这就需要设置响应的更新机制,MFC给我们提供了这种更新机制,利用MFC编程时,菜单项的状态的维护依赖于UPDATE_COMMAND_UI消息,但是只能应用于菜单项。

下面是一个示例,使得我们可以控制编辑下面的剪切是否可用

1.添加剪切更新处理命令



2.定义更新响应函数



这样我们就可以对剪切这个菜单项,进行状态的设置。

**下面介绍些MFC命令更新机制的原理:

当要显示菜单的时候,西永发出WM_INITMENUPOPUP消息,然后由程序窗口的基类接管,他会创建一个CCmdUI对象,并与程序子菜单的第一个菜单项关联,调用该对象的一层成员函数DoUpdate(),这个函数发出UPDATE_COMMAND_UI消息,这条消息带有一个指向CCmdUi的对象指针。这时,系统会判断该类是否有ON_UPDATE_COMMAND_UI宏去捕获这个菜单项消息,找到就调用响应函数处理,当更新完第一个菜单项后,同一个CCmdUI对象就设置为与第二个菜单项相关联,依次顺序进行,直到完成所有菜单项的处理。这就是MFC菜单项的命令更新机制。**

七,总结

这次主要介绍了菜单相关的编程技术,都是基本的API使用和概念,打牢基础很重要,下面是本次使用的资料。

自己总结的思维导图



网盘资料:https://yunpan.cn/cPbJkXRRvnkNe 访问密码 0a8f
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: