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;