1、MFC类层次结构图:

 

CxxxApp类和CxxxDoc类不是CWnd派生,所以没有成员函数MessageBox,可以使用应用程序框架的函数:AfxMessageBox()代替,原型如下:

Int AfxMessageBox(LPCTSTR lpszText,UINT nType=MB_OK,UINT nIDHelp=0);

2、程序类对菜单命令的响应顺序:

视类、文档类、框架类、应用程序类。

3、windows消息分类

(1)标准消息

以WM_开头。

(2)命令消息

来自菜单、加速键或工具栏按钮的消息。都以WM_COMMAND形式呈现。MFC中,通过菜单项的标识(ID)识别;SDK中通过消息的wParam参数识别。

(3)通告消息

由控件产生,例如:按钮的单击、列表框的选择等都会产生这类消息,目的是为了向其父窗口(通常是对话框)通知事件的发生。

结论:

从CWnd派生的类均可继承以上三种消息。

从CCmdTarget派生的类只能接收命令消息和通告消息。

4、菜单命令路由通经

 

 

4、基本菜单操作

(1)获得程序的菜单栏,CWnd::GetMenu()函数,原型如下:

CMenu * GetMenu() const;

返回的是一个CMenu对象指针,可以进行菜单的创建、更新、销毁以及调用其子菜单GetSubMenu函数,原型如下:

CMenu * GetSubMenu(int nPos) const;   //子菜单的索引号

(2)为菜单项添加或移除标记,CMenu::CheckMenuItem()函数,原型如下:

UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck);

参数含义:指定处理的菜单项,如何处置(MF_CHECKED,MF_UNCHECKED,MF_BYPOSITION,MF_BYCOMMAND)

(3)例如:(红字部分配对使用)

GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_SAVE,MF_BYCOMMAND|MF_CHECKED);

GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION|MF_CHECKED);

6、默认菜单项(黑体字标识)

设置默认菜单项,CMenu::SetDefaultItem()函数,原型如下:

BOOL SetDefaultItem(UINT uItem,BOOL fByPos=FALSE);

参数含义:若为false,第一个参数表示菜单项标识,否则为菜单项位置索引。

结论:

(1)一个子菜单只能有一个默认菜单项。

(2)分隔栏在菜单项中占据索引位置。

7、图形标记菜单

实现图形标记菜单利用CMenu::SetMenuItemBitmaps(),作用是将指定位图与菜单项关联,原型如下:

BOOL SetMenuItemBitmaps(UINT nPosition,UINT nFlags,const CBitMap * pBmpUnChecked,const * CBitMap pBmpChecked);

参数描述:菜单项标识|菜单项位置索引,MF_BYCOMMAND,未选中状态位图,选中状态位图。

m_bitmap.LoadBitmap(IDB_BITMAP1);   //m_bitmap为全局变量

GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION|MF_CHECKED,&m_bitmap,&m_bitmap);

//获取标记菜单项上标记图形的默认尺寸:标记宽度,标记高度

GetSystemMetrics(SM_CXMENUCHECK);

8、禁用菜单项

设置菜单项的状态:能够使用、禁用或变灰显示。CMenu::EnableMenuItem(),原型如下:

UINT EnableMenuItem(UINT nIDEnableItem,UINT nEnable);

GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_BYPOSITION|MF_DISABLED|MF_GRAYED);

注意:

//需将CMainFrame类的构造函数中成员变量m_bAutoMenuEnable设置为false。

9、移除和装载菜单

CWnd::SetMenu(),函数原型如下:

BOOL SetMenu(CMenu * pMenu);

例如:

(1)SetMenu(NULL);   //移除

(2)CMenu menu;

 menu.LoadMenu(IDR_MAINFRAME);

 SetMenu(&menu);

     //将菜单句柄和菜单对象分离

 menu.Detach();   //以防程序出现问题 因为此时的menu为一个局部变量

10、MFC菜单命令更新机制

(1)当要显示菜单时,操作系统发出WM_INITMENUPOPUP消息,然后由应用程序窗口的基类如CFrameWnd接管,它会创造一个CCmdUI对象,并与程序的第一个菜单项相关联,调用该对象的一个成员函数DoUpdate(),该函数发出ON_UPDATE_COMMAND_UI消息,这条消息带有一个指向CCmdUI对象的指针。系统判断是否存在一个ON_UPDATE_COMMAND_UI的宏,如果存在就调用相应的函数处理,在该函数中,可以利用传递过来的CCmdUI对象去调用,使用某个菜单项或禁用某个菜单项。更新完第一个菜单后,同一个CCmdUI对象就设置为第二个菜单项相关联,依次进行,直到完成所有菜单项的处理。

 

 

(2)CCmdUI类成员变量m_nID,用于保存当前菜单项、工具栏按钮,或者其他由CCmdUI对象表示的UI对象的标识。

(3)CCmdUI类成员变量m_nIndex,用于保存当前菜单项的位置索引。

8、快捷菜单

1

void CMenuView::OnContextMenu(CWnd*, CPoint point)

{

CMenu* pPopup = menu.GetSubMenu(0);

。。。。

pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,

pWndPopupOwner);

}

其中TrackPopupMenu原型如下:

BOOL TrackPopupMenu(UINT nFlags,int x,int y,CWnd * pWnd,LPCRECT lpRect=NULL)

nFlags:指定菜单在屏幕上显示的位置。

x,y:指快捷菜单显示位置处的x,y坐标。相对于屏幕坐标而不是客户区坐标(ClientToScreen(&point)使用该函数进行转化)

pWnd:指定快捷菜单的拥有者。

lpRect:指定一块矩形区域。鼠标点击其他处该快捷菜单也不会消失。

(2)区别

pPopup ->TrackPopupMenu(TPM_RIGHTBUTTON|TPM_LEFTALIGN,point.x,point.y,this);

pPopup ->TrackPopupMenu(TPM_RIGHTBUTTON|TPM_LEFTALIGN,point.x,point.y,Get Parent());//这种方法好像不对,编译不通过

9、动态菜单操作(针对弹出式菜单动态操作、针对菜单项的动态操作)

(1)动态的添加菜单项目,CMenu::AppendMenu函数原型如下:

BOOL AppendMenu(UINT nFlags,UINT_PTR nIDNewItem=0,LPCTSTR lpszNewItem=NULL);  末尾添加

nFlags:新添加菜单项目的状态信息。(禁用加灰菜单、移除对号标记菜单等)

nIDNewItem:如果第一个参数为MF_POPUP,则为顶层菜单句柄;否为新菜单项的命令ID。

            如果第一个参数为MF_SEPARATOR,nIDNewItem值忽略。

lpszNewItem:如果第一个参数为MF_STRING,则指向新添加菜单项目的文本的指针。

           如果第一个参数为MF_OWNERDRAW,则指向该菜单项目一个附加数据指针。

           如果第一个参数为MF_SEPARATOR,lpszNewItem值忽略。

(2)CMenu::CreatePopupMenu,作用:创建一个弹出菜单并关联菜单对象。

(3)插入菜单项:(在两个子菜单项中添加,在两个菜单项中添加)CMenu::InsertMenu()

BOOL InsertMenu(UINT nPosition,UINT nFlags,UINT_PTR nIDNewItem=0,LPCTSTR lpszNewItem=NULL) 根据具体位置添加

参数含义同AppendMenu函数,但nFlags会多几个组合MF_BYPOSITION和MF_BYCOMMAND.

(4)删除菜单项CMenu::DeleteMenu(),原型如下:

BOOL DeleteMenu (UINT nPosition,UINT nFlags);

13、动态添加菜单项的命令响应:

(1)Resource.h 中添加预定义内容  #define IDM_HELLO 111

(2)menu.AppendMenu(MF_STRING,IDM_HELLO,"hello");

(3)MainFrm.h文件中 AFX_MSG之后,DECLARE_MESSAGE_MAP之前添加:afx_msg void OnHello();

(4)MainFrm.cpp文件中BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加:

ON_COMMAND(IDM_HELLO,OnHello)不加分号。

(5)MainFrm.cpp文件中实现函数OnHello的实体

void CMainFrame::OnHello()

{

MessageBox("hello");

}

14、框架类窗口截获菜单命令消息(不用在视类中处理)

方法是:在框架类中添加OnCommand虚函数.    return TRUE;//中断消息路由路径。

(1)框架类获取视类的成员变量

CMainFrame::GetActiveView成员函数,获取与框架类相关联的当前视类的指针。原型如下:CView * GetActiveView()const; // 返回的是CView,如果不是用户所需还需类型转换。

例如:CTelNoteView * pView=(CTelNoteView *)GetActiveView();  //获取当前视类指针。

(2)m_bAutoMenuEnable=FALSE;