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. //获取当前视类的指针