1、要构建弹出式菜单,要将控件的属性中“Popup”由“false”改为“TRUE”;一般顶级菜单才可以
2、对于一个菜单命令消息函数响应的顺序:CView类→CDoc类→CMainFrame类→CApp类;子窗口享有最先响应的权利,如何子窗口没有,那么交由父窗口
3、消息的分类:
- 标准消息:除WM_COMMAND之外,所有以WM_开头的消息。从CWnd派生的类,都可以接收到这类消息。
- 命令消息:来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。
- 通告消息:由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。从CCmdTarget派生的类,都可以接收到这类消息。
4、命名消息的路由:
5、对于菜单栏中的菜单项可以通过ID号或者索引来访问,而对于子菜单项则通过索引来访问;
6、GetMenu返回一个指向菜单栏的指针,而GetSubMenu返回一个指向子菜单的指针
1 GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION |MF_CHECKED); 在文件->新建前面打上标号
7、获取子菜单项的文本的宽与高:
1 CString str; 2 str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CXMENUCHECK)); 3 MessageBox(str);
8、Detach的使用:Detach将一个CMenu对象和窗口的句柄断开,当程序结束时,析构函数不会析构CMenu对象,而窗口关闭时候,对象才被析构
1 SetMenu(NULL); 2 CMenu menu; 3 menu.LoadMenu(IDR_MAINFRAME); 4 SetMenu(&menu); 5 menu.Detach();
9、命令更新:(CCmdUI类)(主要用来使子菜单项能否使用或者不能使用)
- 菜单项状态的维护是依赖于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处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。
10、TrackPopupMenu用来创建弹出菜单
1 void Cmfctest11View::OnRButtonDown(UINT nFlags, CPoint point) 2 { 3 // TODO: 在此添加消息处理程序代码和/或调用默认值 4 CMenu menu; 5 menu.LoadMenu(IDR_MENU1); //IDR_MENU1为弹出菜单的标识(ID) 6 CMenu* pOldMenu=menu.GetSubMenu(0); 7 ClientToScreen(&point); //客户坐标转化到窗口坐标 8 pOldMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this);//如果想要MainFrame有响应机会,必须将this改为GetParent() 9 CView::OnRButtonDown(nFlags, point); 10 }
11、在窗口菜单栏(末尾)动态添加菜单
1 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 2 { 3 if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 4 return -1; 5 6 if (!m_wndStatusBar.Create(this)) 7 { 8 TRACE0("未能创建状态栏\n"); 9 return -1; // 未能创建 10 } 11 m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)); 12 //在窗口菜单栏动态添加菜单 13 CMenu menu; 14 menu.CreatePopupMenu(); 15 GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"weixin"); 16 menu.Detach(); //不加这个会提示错误,该函数实现menu这个对象与窗口句柄的断开 17 return 0; 18 }
12、在窗口菜单栏的两个菜单之间插入新的菜单
1 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 2 { 3 if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 4 return -1; 5 6 if (!m_wndStatusBar.Create(this)) 7 { 8 TRACE0("未能创建状态栏\n"); 9 return -1; // 未能创建 10 } 11 m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)); 12 //在窗口菜单栏的两个菜单之间插入新的菜单 13 CMenu menu; 14 menu.CreatePopupMenu(); 15 GetMenu()->InsertMenu(2,MF_POPUP|MF_BYPOSITION,(UINT)menu.m_hMenu,"weixin");//插入新的菜单 16 menu.AppendMenu(MF_STRING,111,"Hello"); //在新插入菜单中,添加菜单项 17 menu.AppendMenu(MF_STRING,112,"weixin"); 18 menu.AppendMenu(MF_STRING,113,"mybole"); 19 menu.Detach(); //不加这个会提示错误,该函数实现menu这个对象与窗口句柄的断开 20 return 0; 21 }
13、手动添加菜单的响应函数:
- 添加资源标识(ID):在Resource.h中,添加标识
#define IDM_HELLO 111
2. 添加消息映射:
1 // 生成的消息映射函数,在MainFrm.h文件中添加 2 protected: 3 afx_msg void OnHello();
1 // CMainFrame,在MainFrm.cpp文件添加 2 3 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) 4 5 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 6 ON_WM_CREATE() 7 ON_COMMAND(IDM_HELLO,OnHello) 8 END_MESSAGE_MAP()
3.命令函数的实现:
1 // CMainFrame 消息处理程序 2 void CMainFrame::OnHello() 3 { 4 MessageBox("Hello!"); 5 ...... 6 }
14、如果窗口已经创建,而菜单栏已经发生改变,则要调用DrawMenuBar()对菜单栏的重画,CVIew中没有此函数,CMainFrame中有;Invalidate()判断是否对背景的擦除;CStringArray标识CString类的集合类(类似数组)
15、低字节序(一个四位数的前面两位),高字节序(一个四位数的后面两位),用LOWORD()来取出,
16、在CFrameWnd类中调用函数指向当前的CView类,并返回指针
CMenu2View *pView=(CMenu2View*)GetActiveView();
17、若在文件中检查出错误,如下面的
Public: CMenu2Doc* GetDocment(); 弹出错误:missing ';' before '*' 这时要检查该头文件中有没有包含:"Menu2Doc.h"