1.当对某菜单添加消息响应函数时,4个类的消息响应优先次序分别是:a.View;b.CDOC;c.CMainFrame.d.CWinAPP.为什么?请参阅《深入浅出》
2.消息分类:a;标准消息(以WM_开头的消息,但不包括ON_COMMAND);b;命令消息ON_COMMAND(IDM_PHONE1, OnPhone1),菜单和工具栏的消息。c.通告消息:按钮,列表框发出的消息。
CCmdTarget只能接受命令消息。而从CCmdTarget派生的CWnd可以接收命令消息,也可以接受标准消息。
3.确定菜单的索引号,注意从0开始,分隔符也算数。什么叫弹出菜单(Popup Menu)?一个子菜单只能有一个缺省菜单。 //GetMenu()->GetSubMenu(0)->SetDefaultItem(5,TRUE);
str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),
GetSystemMetrics(SM_CYMENUCHECK));//获得系统的菜单的位图的大小。
/* SetMenu(NULL);//移除菜单 CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
menu.Detach();*/增加菜单,此处detach(),如果是局部变量。
4.
void CMainFrame::OnUpdateEditCut(CCmdUI* pCmdUI)
{
if(2==pCmdUI->m_nIndex)
pCmdUI->Enable();//当此菜单显示时,设为可用。
}
5.右键弹出菜单功能的实现方法有两个:
a.Project->Add to Project->component and controls->文件夹VC components->Popup Menu OK
b.用TrackPopupMenu()实现。
CMenu menu;
menu.LoadMenu(IDR_MENU1);
CMenu *pPopup=menu.GetSubMenu(0);
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
GetParent());
6.动态创建菜单的方法: CMenu menu;
menu.CreatePopupMenu();
// GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"WinSun");
GetMenu()->InsertMenu(2,MF_BYPOSITION | MF_POPUP,(UINT)menu.m_hMenu,"WinSun");
menu.AppendMenu(MF_STRING,IDM_HELLO,"Hello");
menu.AppendMenu(MF_STRING,112,"Weixin");
menu.AppendMenu(MF_STRING,113,"Mybole");
menu.Detach();
GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"Welcome");
GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,
MF_BYCOMMAND | MF_STRING,115,"维新");
// GetMenu()->DeleteMenu(1,MF_BYPOSITION);
// GetMenu()->GetSubMenu(0)->DeleteMenu(2,MF_BYPOSITION);
7.为动态创建的菜单增加消息响应的步骤
a.在resource.h中增加#define IDM_HELLO 123
b.在MainFrm.h中加入afx_msg void OnHello();
c.MainFrm.cpp中加入ON_COMMAND(IDM_HELLO,OnHello)
d.最后加入
void CMainFrame::OnHello()
{
MessageBox("Hello!");
}
8.动态增加电话号码本步骤
a.处理WM_Char消息。如果回车,则清空字符串,窗口重绘invalidate,将人名加入到菜单中,将字符串保存集合类CStringArray中,用的是成员函数Add方法。
b.取出动态创建的菜单的数据的方法。
1)创建一个弹出菜单,弹出菜单下面有4个子菜单。将子菜单的ID号连续。
2)在resource.h中添加#define IDM_PHONE1 123....
3)添加其消息响应函数。注意注释中的文字
BEGIN_MESSAGE_MAP(CMenu2View, CView)
//{{AFX_MSG_MAP(CMenu2View)
ON_WM_CHAR()
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)//下面的4句代码原来在此处。
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(IDM_PHONE1, OnPhone1)//一定要这4句代码移到此处。
ON_COMMAND(IDM_PHONE2, OnPhone2)
ON_COMMAND(IDM_PHONE3, OnPhone3)
ON_COMMAND(IDM_PHONE4, OnPhone4)
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
4)填写代码
9.如何在MainFrame中拦截OnCommand消息?答,在它增加OnCommand的消息处理函数即可。
10.错误调试方法:Missing ";" before "*"
CMenu2Doc* GetDocument();//因为CMenu2Doc是个不认识的变量,将其头文件包含进即可。
这个视频长达3个多小时,把程序分成了三个程序:
具体代码如下:
Menu:
CMainFrame.h
- private:
- CBitmap cbitmap;
- CString cstring;
CMainFrame中的OnCreate:
- //GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION|MF_CHECKED);
- //GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND|MF_CHECKED);
-
- //GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_NEW,FALSE);//其中FALSE可以不写,默认的
- //GetMenu()->GetSubMenu(0)->SetDefaultItem(5,TRUE);//其中分割线也算一个索引,而且一个子菜单中,只能有一个缺省菜单
-
- /*
- //CString的成员函数,格式化输出,相当于windows32的wsprintf,输出菜单位图的大小
- cstring.Format("x=%d,y=%d",::GetSystemMetrics(SM_CXMENUCHECK),::GetSystemMetrics(SM_CYMENUCHECK));
- this->MessageBox(cstring);//弹出一个box,x=13,y=13
- */
-
- //cbitmap.LoadBitmap(MAKEINTRESOURCE(BITMAPID));//cbitmap要设置为成员变量,画位图的时候,位图是13X13的
- //GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(1,MF_BYPOSITION,&cbitmap,&cbitmap);
-
- //这里要在CMainFrame构造函数添加一行:m_bAutoMenuEnable =FALSE;这样下面的语句才有效,但是Edith的菜单选项却变成有效的了
- //GetMenu()->GetSubMenu(0)->EnableMenuItem(2,MF_BYPOSITION|MF_DISABLED|MF_GRAYED);
-
- /*只是这样是有问题的,有两种解决方法,一种方法是将cmenu设置称为成员变量
- SetMenu(NULL);//CWnd的成员函数,如果参数为NULL,则移除菜单
- CMenu cmenu;
- cmenu.LoadMenu(IDR_MAINFRAME);
- SetMenu(&cmenu);//把菜单设置回来
- */
-
- /*解决方法二,只是按照孙鑫老师方法,只是添加一条cmenu.Detach(),运行,菜单都不见了
- SetMenu(NULL);
- CMenu cmenu;
- cmenu.LoadMenu(IDR_MAINFRAME);
- HMENU hmenu=cmenu.Detach();
- CMenu *ccmenu=CMenu::FromHandle(hmenu);
- SetMenu(ccmenu);
- */
CBitMap:
CMenu:
一种利用向导生成 浮动菜单
- void CMainFrame::OnRButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- ClientToScreen(&point);
- CMenu menu;
- menu.LoadMenu(MAKEINTRESOURCE(MENUID));
-
- CMenu *ppopmenu=menu.GetSubMenu(0);
-
- ppopmenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);
-
-
- CFrameWnd::OnRButtonDown(nFlags, point);
- }
也可以自己手动设置:
在CXXView中
- void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
-
- ClientToScreen(&point);//客户端转化为屏幕坐标
- CMenu menu;
- menu.LoadMenu(MAKEINTRESOURCE(MENUID));
-
- CMenu *ppopmenu=menu.GetSubMenu(0);
-
- ppopmenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);
-
- CView::OnRButtonDown(nFlags, point);
- }
上面的CMenu是自己添加生成的菜单,
然后去资源头文件,添加三个ID
然后利用向导,可以添加消息响应时间。
设置菜单是否可用:
- void CMenuView::OnUpdateFileNew(CCmdUI* pCmdUI)
- {
- // TODO: Add your command update UI handler code here
-
- if(0==pCmdUI->m_nIndex)//这步可有可无,先比较索引
- pCmdUI->Enable(FALSE);
- }
-
- void CMenuView::OnUpdateEditCut(CCmdUI* pCmdUI)
- {
- // TODO: Add your command update UI handler code here
- if(ID_EDIT_CUT==pCmdUI->m_nID)//先比较ID,如果用索引的话,工具栏的图标跟菜单的状态不一定能对上号
- pCmdUI->Enable();//默认参数是TRUE
- }
下面是程序2 动态添加菜单
Menu2:
CMainFrame中OnCreate:
- //将menu设置成为成员变量
- menu.CreatePopupMenu();
- //GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"CSDN");//当第一项参数为MF_POPUP(子菜单)的时候,第二个参数用句柄
- //GetMenu()->InsertMenu(1,MF_BYPOSITION|MF_POPUP,(UINT)menu.m_hMenu,"CSDN");//标志位可以组合,使用或运算
- //GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,110,"CSDN");//第一项参数为MF_STRING(子选项)时候,第二参数为整数
- //GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_BYCOMMAND|MF_STRING,(UINT)m_hWnd,"CSDN");
-
- //GetMenu()->DeleteMenu(1,MF_BYPOSITION);//删除第二个子菜单
- //GetMenu()->GetSubMenu(1)->DeleteMenu(ID_EDIT_COPY,MF_BYCOMMAND);//删除第二个子菜单中的复制选项
-
- GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"CSDN");
- menu.AppendMenu(MF_STRING,ID_ZICAIDANYI,"zicaidai1");
- menu.AppendMenu(MF_STRING,ID_ZICAIDANER,"zicaidan2");
- menu.AppendMenu(MF_STRING,115,"zicaidan3");
纯手工写菜单,上面已经添加了菜单,下面添加事件。
Resource.h添加MenuID
然后在下面三个地方添加如下代码:
1MainFrM.h添加事件函数原型
2MainFrm.cpp添加消息映射
3MainFrm.cpp添加事件处理代码
- void CMainFrame::OnZICAIDANYI()
- {
- MessageBox("你点击了子菜单1");
- }
-
- void CMainFrame::OnZICAIDANER()
- {
- MessageBox("你点击了子菜单2");
- }
程序3
创建动态电话本
- void CMenu3View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
- {
- // TODO: Add your message handler code here and/or call default
-
-
-
-
- //cmenu.CreatePopupMenu();
- //GetMenu()->GetSubMenu(0)->AppendMenu(MF_POPUP,(UINT)cmenu.m_hMenu,"TEST");
-
-
- CClientDC ccdc(this);
-
-
- if(0x0d==nChar)
- {
-
- if(0==++m_count)
- {
- cmenu.CreatePopupMenu();
- GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)cmenu.m_hMenu,"PhoneBook");
- //View类是没有菜单的,是CMainFrame的菜单,CMainFrame是View的父类,所以GetParent();
-
-
- GetParent()->DrawMenuBar();//拥有Menu的类去调用DrawMenuBar,当Menu有改变的时候,重绘
- }
-
- cmenu.AppendMenu(MF_STRING,ID_PHONE1+m_count,cstring.Left(cstring.Find(' ')));
- cstringarray.Add(cstring);
- cstring.Empty();
- Invalidate();
- SetCaretPos(m_yuandian);
-
- }
- else
- {
- cstring+=nChar;
-
- }
-
-
- CSize cs=ccdc.GetTextExtent(cstring);
- CPoint cpint(m_yuandian.x+cs.cx,m_yuandian.y);
-
- SetCaretPos(cpint);
-
- ccdc.TextOut(m_yuandian.x,m_yuandian.y,cstring);
-
- CView::OnChar(nChar, nRepCnt, nFlags);
- }
跟孙鑫老师的有点不一样,有点改动
- void CMenu3View::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
-
- m_yuandian=point;
- cstring="";
- SetCaretPos(point);
- CView::OnLButtonDown(nFlags, point);
- }
- void CMenu3View::OnPhone1()
- {
- // TODO: Add your command handler code here
-
- CClientDC ccdc(this);
- ccdc.TextOut(0,0,cstringarray.GetAt(0));
-
- }
-
- void CMenu3View::OnPhone2()
- {
- // TODO: Add your command handler code here
-
- CClientDC ccdc(this);
- ccdc.TextOut(0,0,cstringarray.GetAt(1));
- }
-
- void CMenu3View::OnPhone3()
- {
- // TODO: Add your command handler code here
-
- CClientDC ccdc(this);
- ccdc.TextOut(0,0,cstringarray.GetAt(2));
- }
-
- void CMenu3View::OnPhone4()
- {
- // TODO: Add your command handler code here
-
- CClientDC ccdc(this);
- ccdc.TextOut(0,0,cstringarray.GetAt(3));
- }
这里孙鑫老师讲了一个技巧,现在Menu资源创建一个临时菜单,ID号跟代码中要添加的ID一致,然后去Resource.h文件添加了四个ID,也就是代码中要添加的菜单选项的ID分别为刚才在Menu资源中菜单选项添加事件,然后在XX.cpp文件中,把消息映射提取到宏的外面,去Menu资源,把临时菜单删了 最后一个知识点是,用CMainFram截获消息:在CMainFram添加一个虚拟函数OnCommand
- BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
- {
- // TODO: Add your specialized code here and/or call the base class
-
- int MenuCmdid=LOWORD(wParam);
- CMenu3View *pmenu=(CMenu3View*)GetActiveView();
- if(MenuCmdid>=ID_PHONE1 && MenuCmdid<ID_PHONE1+pmenu->cstringarray.GetSize())
- {
- //MessageBox("test");
- CClientDC ccdc(pmenu);
- ccdc.TextOut(0,0,pmenu->cstringarray.GetAt(MenuCmdid-ID_PHONE1));
- return true;
- }
-
-
- return CFrameWnd::OnCommand(wParam, lParam);
- }