CMenuApp 并不是从CWnd派生出来的,所以不能使用MessageBox函数。
但可以使用全局的MessageBox函数:AfxMessageBox函数
int AfxMessageBox(LPCTSTR lpszText,UINT nType,UINT nIDHelp);
对菜单项Test响应的顺序: View-Doc-MainFrame-App
消息的分类
标准消息 除WM_COMMAND之外,所有以WM_开头的消息。从CWnd派生的类,都可以接收到这类消息。
命令消息 来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。
在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;
在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。
通告消息 由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,
为的是向其父窗口(通常是对话框)通知事件的发生。
这类消息也是以WM_COMMAND形式呈现。从CCmdTarget派生的类,都可以接收到这类消息。
CWnd是由CCmdTarget派生
CWnd::GetMenu
CMenu* GetMenu()const;
CMenu封装了一些和菜单有关的操作,封装了windows的HMENU(菜单句柄)
CMenu::GetSubMenu
CMenu* GetSubMenu( int nPos) const; //获取子菜单
CMenu::CheckMenuItem
UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck);// Return the previous state of the item
CMenu::SetDefaultIte
//BOOL SetDefaultItem( UINT uItem, BOOL fByPos=FALSE) //设置缺省的菜单项
指定的缺省菜单项将会被加黑显示
CAUTION! 一个子菜单中,只能有一个缺省菜单项
CMenu::SetMenuItemBitmaps
//BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags,
const CBitmaps* pBmpUnchecked, const CBitmaps* pBmpChecked)
创建图形标记菜单
获取图形标记菜单位图的大小:
int GetSystemMetrics( int nIndex)
nIndex: //system metric or configuration setting
SM_CXMENUCHECK //缺省的菜单标记位图的高度
SM_CYMENUCHECK //缺省的菜单标记位图的宽度
CString str;
str.Format("x=%d, y=%d",GetSystemMetrics(SM_CXMENUCHECK),
GetSystemMetrics(SM_CYMENUCHECK));
MessageBox(str);
//改变菜单项的状态
CMenu::EnableMenuItem
UINT EnableMenuItem( UINT nIDEnableItem, UINT nEnable );
CAUTION! 只有在CMainFrame的构造函数中将变量 m_bAutoMenuEnable=FALSE时,
EnableMenuItem函数才会起作用
m_bAutoMenuEnable=FALSE时MFC就不会使用他的命令更新机制去判断哪个菜单项能使用
哪个菜单项不能使用,此时这些操作都要由我们自己去完成
如何将整个菜单取消:
CWnd::SetMenu
//BOOL SetMenu( CMenu* pMenu);
SetMenu( NULL); //移走当前菜单
重新加载菜单:
CMenu menu; // 不能是局部对象
menu.LoadMenu( IDM_MAINFRAME /×菜单ID*/)//动态的更换菜单
SetMenu(&menu);
menu.Detach();//如果menu是局部对象,一定要调用Detach()函数,它将菜单的句柄和我们的C++对象断开,
这样当局部对象CMenu析构时,不会销毁我们的菜单
MFC对菜单项采用的命令更新机制:01:18:00
命令更新
菜单项状态的维护是依赖于CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,
MFC就在其中创建一个CCmdUI对象。我们可以通过手工或利用ClassWizard在消息映射中添加
ON_UPDATE_COMMAND_UI宏来捕获CN_UPDATE_COMMAND_UI消息。
在后台所做的工作是:操作系统发出WM_INITMENUPOPUP消息,然后由MFC的基类如CFrameWnd接管。
它创建一个CCmdUI对象,并与第一个菜单项相关联,调用对象的一个成员函数DoUpdate()。
这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有指向CCmdUI对象的指针。同一个
CCmdUI对象就设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。
更新命令UI处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。
void CMainFrame::OnUpdateEditCut( CCmdUI* pCmdUI)
{
pCmdUI->Enable();//Enable()函数的缺省参数为 BOOL类型TRUE
}
工具栏上的图标,和它所对应的菜单项的ID号是一样的。所以当对菜单项DISABLE或者ENABLE时能够相应
的在工具栏上显现出来。
CAYTION!:如果在改变菜单项状态的过程中是用的菜单项ID号,则菜单项状态的改变能在工具栏上相应的
图标上显现出来,但如果使用的是菜单项的位置索引,则相应的状态不会在工具栏上显现出来。
这是因为工具栏上的图标和相应菜单项具有相同的ID号,但位置索引是不相同的。
实现右键弹出菜单的功能:
Project->Add To Project->Components and Controls->Visual C++ Components->Pop-up Menu
注意:应该把菜单加入CMenuView类
此时,会在CMenuView类中加入一个函数OnContextMenu( CWnd* , CPoint)
//CWnd::OnContextMenu
//afx_msg void OnContextMenu( CWnd* pWnd,CPoint pos)
//Called by framework when the user has clicked the right mouse button(right clicked)
//in the window.You can process(处理)this message by displaying a context menu using the
//TrackPopupMenu(用来显示弹出菜单)
CMenu:: TrackPopupMenu
//BOOL TrackPopupMenu( UINT nFlags, //弹出菜单相对于x的位置
int x, int y, //鼠标点击的位置坐标,注意这个位置坐标是相对于屏幕坐标
//而不是客户区坐标,使用是需要进行坐标转换
CWnd* pWnd, //菜单的拥有者
LPCRECT lpRect=NULL //指定一个矩形,当鼠标在矩形外点击时,菜单消失
//在矩形内点击时,弹出菜单不消失
);
坐标转换:
CWnd::ClientToScreen
void ClientToScreen( LPPOINT lpPoint) const;
void ClientToScreen( LPRECT lpRect) const;
为弹出菜单的“显示”菜单项,在CMenuView和CMainFrame类中分别加入命令捕获OnShow函数
选中“显示”项,发现只有CMenuView类对菜单命令进行捕获,原因是用TrackPopupMenu显示弹出
菜单时,指定了弹出菜单的拥有者窗口指针
即使将指针设置为父窗口指针,子窗口依然最先响应菜单命令,只有当子窗口不响应时,才交由父窗口响应
通过代码来动态添加菜单
CMenu::AppendMenu
//BOOL AppendMenu( UINT nFlags, UINT nIDNewItem=0, LPCTSTR lpszNewItem=NULL);
//BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp);
//可以将一个菜单或者一个菜单项添加到现有菜单的末尾
//nFlags: MF_STRING MF_POPUP MF_SEPARATOR
//nIDNewItem:当nFlags=MF_POPUP,则nIDNewItem为POPUP菜单的句柄
//当nFlags=MF_SEPARATOR,则nIDNewItem被Ignored
CMenu::CreatePopupMenu
//Creates an empty pop-up menu and attaches it to a CMenu object
//BOOL CreatePopupMenu()
插入菜单
CMenu::InsertMenu
//BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem=0,LPCTSTR lpszNewItem);
//BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem,const CBitmap* pBmp);
//nPosition的取值由nFlags来确定,如果nFlags=MF_BYPOSITION,则nPosition为位置所以号
//如果nFlags=MF_BYCOMMAND,则nPosition为菜单项ID号
//nIDNewItem:当nFlags=MF_POPUP,则nIDNewItem为POPUP菜单的句柄
//当nFlags=MF_SEPARATOR,则nIDNewItem被Ignored
删除子菜单
CMenu::DeleteMenu()
//BOOL DeleteMenu( UINT nPosition, UINT Flags); //删除一个指定的菜单项或弹出菜单
对动态创建的菜单项进行命令响应
头文件Resource.h定义了资源的ID
做一个菜单命令的命令响应函数,它的添加和消息响应函数时一样的,一共有三个步骤:
step1:首先在头文件中做命令响应函数的原型
//MainFrm.h
//protected:
//afx_msg void OnHello();
step2: 消息映射 //使用教程中的方法时,消息映射一定要放到注释宏的外面
//MainFrm.cpp
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_COMMAND(IDM_HELLO/*ID号*/,OnHello/*命令响应函数*/) //注意!不要加任何的标点符号
END_MESSAGE_MAP()
step3:命令响应函数的实现
//MainFrm.cpp
void CMainFrame::OnHello()
{
MessageBox("Hello!");
}
编写电话本程序
注:菜单栏是属于框架窗口的,在view类中调用GetMenu()是无法获得指向菜单的指针的,因为view窗口根本
没有菜单
对菜单栏进行重绘
CWnd::DrawMenuBar
void DrawMenuBar()
//Redraw the menu bar .If a menu bar is changed after windows has created the window,
//cal the function to draw the changed menu bar.
利用父窗口(框架窗口)调用DrawMenuBar
对窗口进行重绘
CWnd::Invalidate
//void Invalidate( BOOL bErase=TRUE)
CString的查找功能
CString::Find
int Find( TCHAR ch)const;
int Find( LPCTSTR lpszSub)const;
int Find( TCHAR ch, int nStart)const;
int Find( LPCTSTR pstr, int nStart)const;
Return Value
返回基于0的第一个匹配的字符(串)索引,如果找不到,返回-1
存储字符串集合类 CStringArray
CWnd::OnCommand
//virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam) 虚函数
//The framework calls this member function when the user selects an item from a menu,when a
//child control sends a notification message(通告消息),or when an accelerator keystroke is
//translated
//OnCommand 处理消息映射
如何得到框架窗口下的视图窗口的指针:
CFrameWnd::GetActiveView
CView* GetActiveView() const;
Return Value
A point to the current CView.If there is no current view, returns NULL.
//获取当前视类的指针