提示:MFC都是采用大写字母来标识资源ID号的;为了区分资源类型,通常遵循这样一个原则:在“ID”字符串后加上一个标识资源类型的字母。例:菜单资源(Menu):ID_Mxxx;光标资源(Cursor):ID_Cxxx;图标资源(Icon):ID_Ixxx等;编程
程序类对菜单命令的响应顺序:视类、文档类、框架类、应用程序类框架
xxxView --> xxxDoc --> xxxFrame --> xxxApp(能够经过调试验证,注意:CxxxApp类 和 CxxxDoc类 都不是从CWnd类派生的,故都没有MessageBox成员函数,因此要使用全局的MessageBox函数,或者使用应用程序框架的函数:AfxMessageBox)ide
int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );
Windows消息的分类:函数
·标准消息 除WM_COMMAND以外,全部以WM_开头的消息。 从CWnd派生的类,均可以接收到这类消息。工具
·命令消息 来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,经过菜单项的标识(ID)来区分不一样的命令消息;在SDK中,经过消息的wParam参数识别。 从CCmdTarget派生的类,均可以接收到这类消息。this
·通告消息 由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(一般是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。 从CCmdTarget派生的类,均可以接收到这类消息。spa
CWnd类派生于 CCmdTarget类;即:凡是从CWnd派生的类,他们既能够接收标准消息,也能够接收命令消息和通告消息。而对于那些从CCmdTarget派生的类,则只能接收命令消息和通告消息,不能接收标准消息。(文档类、视图类 派生于 CCmdTarget类)操作系统
**菜单命令的路由:3d
菜单命令消息响应函数的映射与“4_简单绘图”中介绍的标准消息的映射是同样的,只是消息命令使用的是ON_COMMAND宏。可是:命令消息和标准消息的路由过程仍是有区别的。指针
提示:WindowProc函数是CWnd类的一个成员函数。
3、菜单的结构:
整个楼房对应于程序中的菜单栏,楼房的每一层对应于菜单栏上的子菜单(如:文件、编辑、查看、帮助等菜单对象),而房间对应于菜单项。
注意:分隔栏在(子)菜单中是占据索引位置的。
程序的主菜单属于框架窗口,因此须要在框架类窗口建立完成以后再去访问菜单对象。能够在框架类(CMainFrame类)的OnCreate函数的最后(return以前)添加对菜单功能操做的代码。
//CWnd::GetMenu CMenu* GetMenu( ) const;
·功能:在框架窗口中得到指向菜单栏的指针;CMenu类是一个MFC类,是Windows菜单句柄HMENU的一个封装,提供一些与菜单操做有关的成员函数,例如:菜单的建立、更新和销毁等,还能够得到一个菜单的子菜单,以下:
//CMenu::GetSubMenu CMenu* GetSubMenu( int nPos ) const;
·功能:获取一个菜单的子菜单;
·nPos:指定子菜单的索引号;
·返回一个指向CMenu对象的指针,该函数返回值所指向的对象与CWnd类的GetMenu函数的返回值所指向的对象不同;GetMenu函数返回的是指向程序菜单栏对象的指针,而GetSubMenu成员函数返回的是由参数nPos指定的子菜单的指针。
注意:GetMenu函数是CWnd类的成员函数,而GetSubMenu函数是CMenu的成员函数。
//CMenu::CheckMenuItem UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck );
·功能:为菜单项添加一个标记,或者移除菜单项的标记;
·nIDCheckItem:指定须要处理的菜单项,它的取值由第二个参数决定。
·nCheck:指定怎样设置菜单项,以及如何定位该菜单项的位置;取值能够是:MFCHECKED 或 MF_UNCHECKED 与 MF_POSITION 或 MF_BYCOMMAND的组合;
如: GetMenu()->GetSubMenu(0)->ChechMenuItem(0, MF_BYPOSITION | MF_COMMOD); 此为位置访问菜单项,也可用菜单标识访问。
//CMenu::SetDefaultItem BOOL SetDefaultItem( UINT uItem, BOOL fByPos = FALSE );
·做用:设置默认菜单项;
·uItem:取值由第二个参数决定;能够是新的默认喜好单项的表示或位置索引,值为-1,代表没有默认菜单项。
·fByPos:值为FALSE,代表第一个参数是菜单项标识,不然是菜单项位置索引;
·一个子菜单只有一个默认菜单项;
图形标记菜单:
//CMenu::SetMenuItemBitmaps BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked );
·做用:将指定的位图与菜单项关联起来(菜单项前面有小图标);
·第一个参数(nPosition)的取值也是由第二个参数(nFlags)的值决定;
·第三个参数:指定当取消菜单项选中状态时的位图,
·第四个参数:指定选中菜单项时显示的位图(固然能够都指定同一个位图,也能够指定不一样的位图);
注意:bitmap是全局变量仍是局部变量这很关键,它们的做用周期不一样,会致使不同的结果。
int GetSystemMetrics( int nIndex // system metric or configuration setting );
·做用:用来指定但愿获取那部分系统信息;
·nIndex:当值为SM_CXMENUCHECK或SM_CYMENUCHECK时,该函数将获取标记菜单项上标记图形的默认尺寸,前者是得到标记图形的宽度,后者是得到标记图形的高度(还有不少其余的取值,参见MSND)。
禁用菜单项:
//CMenu::EnableMenuItem UINT EnableMenuItem( UINT nIDEnableItem, UINT nEnable );
// NOTE: m_bAutoMenuEnable is set to FALSE in the constructor of // CMainFrame so no ON_UPDATE_COMMAND_UI or ON_COMMAND handlers are // needed, and CMenu::EnableMenuItem() will work as expected.
·做用:设置菜单项的状态:可以使用、禁用或变灰显示。
·第一个参数有第二个参数决定。后者能够是MF_DISABLED, MF_ENABLED 或 MF_GRAYED 与 MF_BYCOMMAND(指定第一个参数是菜单项的标识ID) 或 MF_BYPOSITION(指定第一个参数是菜单项的位置索引) 的组合。
·提示信息:一旦在CMainFrame类的构造函数中把成员变量m_bAutoMenuEnable设置为FALSE后,就不须要对ON_UPDATE_COMMAND_UI 或 ON_COMMAND 消息进行响应处理了,CMenu类的EnableMenuItem函数将可以正常工做。(默认状况下,全部菜单项的更新都是由MFC的命令更新机制完成的。若是咱们想本身更改菜单项的状态,那就必须先把 m_bAutoMenuEnable 变量设置为FALSE,以后,咱们本身对相爱但想的状态更新才能起做用)
CMainFrame::CMainFrame() { //TODO:ADD menber initialization code here m_bAutoMenuEnable = FALSE; }
·将m_bAutoMenuEnable设置为FALSE后,MFC就再也不利用它的菜单命令更新机制去判断哪一个菜单可使用,那个菜单不可以使用,因此其也就不能根据菜单项的状态以不一样的外观来显示;而菜单可否使用这些判断操做,就须要咱们本身去完成了。
移除和装载菜单:
//CWnd::SetMenu BOOL SetMenu( CMenu* pMenu );
·pMenu:指向一个新菜单对象。值为NULL,则当前菜单就被移除了。
在编程中,除了使用MFC自动建立的IDR_MAINFRAME菜单之外,还能够本身建立一个菜单资源并加载,而后调用SetMenu函数,从而使程序的菜单编程本身定义的这个菜单;经过这种方式,能够实现动态更换程序菜单的功能。
提示:在设置窗口菜单是,若是定义的是局部菜单对象,则必定要在调用SetMenu函数设置窗口菜单以后,当即调用菜单对象的Detach函数将菜单句柄与菜单对象分离。
//CMenu::Detach HMENU Detach( );
·功能:把菜单句柄与这个菜单对象(局部变量)分离。在“SetMenu(xxx);” 后使用;(SetMenu函数会把窗口的菜单设置为器参数指定的新菜单,到时窗口重绘,以反映菜单的这种变化,同时也将该菜单对象的全部权交由给窗口对象。而税后的Detach函数会把菜单句柄与这个菜单对象分离,这样当这个局部菜单对象的声明周期结束时,它不会去销毁一个它再也不具备拥有权的菜单)
MFC菜单命令的更新机制:
利用MFC编程时,菜单项状态的维护依赖与CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,MFC就在其中那个建立一个CCmdUI对象。(咱们能够经过手工,或利用ClassWizard在消息映射中添加ON_UPDATE_COMMAND_UI宏来捕获CN_UPDATE_COMMAND_UI消息)
图示 为剪切菜单项增长UPDATE_COMMAND_UI消息处理函数
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(IDM_TEST, OnTest) ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)//*消息映射机制自动添加的xxx宏*该宏是用来捕获CN_UPDATE_COMMAND_UI消息的 //}}AFX_MSG_MAP END_MESSAGE_MAP()
当程序框架捕获到了CN_UPDATE_COMMAND_UI消息后,最终仍是交由该消息的响应函数来处理,例如本例中的OnUpdateEditCut函数:
void CMainFrame::OnUpdateEditCut(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here }
·CCmdUI指针类型的参数:利用CCmdUI类,能够决定一个菜单项是否可使用、是否有标记,还能够改变菜单项的文本。(UI(User Interface):用户接口;菜单项 就是一个用户接口)
提示:CN_UPDATE_COMMAND_UI消息的响应只能应用于菜单项,不能应用与永久显示的顶级菜单(即弹出式菜单)项目。
MFC在后台的所作的工做是:当要显示菜单时,操做系统发出WM_INITMENUPOPUP消息,而后有程序窗口的基类如CFrameWnd接管。它会建立一个CCmdUI对象,并与程序的第一个菜单项相关联,调用该对象的一个成员函数DoUpdate()。这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有一个指向CCmdUI对象的指针。这时,系统会判断是否存在一个ON_UPDATE_COMMAND_UI宏去捕获这个菜单项消息。若是找到这样一个宏,就调用响应的消息响应函数进行处理,在这个函数中,能够利用传递过来的CCmdUI对象去调用响应的函数,是该菜单项可使用,或禁用该菜单项。当更新完第一个菜单项后,同一个CCmdUI对象就设置为与第二个菜单项相关联,以此顺序进行,知道完成全部菜单项的处理。这就是MFC命令更新机制。
利用MFC提供的命令更新机制,在程序中实现菜单项的可用或机制功能时就变得很简单了。咱们只须要捕获UPDATE_COMMAND_UI消息,在该消息的响应函数中调用CCmdUI对象的相应函数,如:Enable、SetCheck、或SetText函数,就能够分别实现菜单项可用或禁用、设置标志菜单,或者设置菜单项的文本这些功能。
//CCmdUI::xxx virtual void Enable( BOOL bOn = TRUE ); virtual void SetCheck( int nCheck = 1 ); virtual void SetRadio( BOOL bOn = TRUE ); virtual void SetText( LPCTSTR lpszText ); void ContinueRouting( );
若是要把工具栏上的一个工具按钮与菜单栏中的某个菜单项相关联,只要将他们的ID设置为同一个标识就能够了。
计算菜单项索引时,必定要把分隔栏菜单项计算在内。
综上:若是要在程序中设置某个菜单系那个的状态,首先经过ClassWizard为这个菜单项添加UPDATE_COMMAND_UI消息响应函数,而后在这个函数中进行状态的设置便可。
快捷菜单:
//CMenu::TrackPopupMenu BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );
·做用:显示一个快捷菜单。
快捷菜单建立的步骤;
(1)为Menu程序增长一个新的菜单资源(Menu1)。而后打开菜单资源添加菜单项。如:
(2)给CMenuView类添加WM_RBUTTONDOWN消息响应函数。(若是是在鼠标右键单击窗口时显示快捷菜单,那么就应该捕获这个消息)
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CMenu menu; menu.LoadMenu (IDR_MENU1); CMenu* pPopup = menu.GetSubMenu(0); ClientToScreen(&point);//左边转换,把客户区坐标转换为屏幕坐标 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);//注意:this的不一样,就有不一样的响应 CView::OnRButtonDown(nFlags, point); }
(3)为Menu程序添加快捷菜单上个菜单项命令的响应函数。
提示:对于快捷菜单,若是将其拥有者窗口设置为框架类窗口,则框架类窗口才能有机会得到对该快捷菜单中的菜单项的命令响应,不然,就只能有视类窗口作出响应。
动态菜单操做
未完待续···