MFC(菜单,孙鑫C++第六讲笔记整理)

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是个不认识的变量,将其头文件包含进即可。

 

MFC(菜单,孙鑫C++第六讲笔记整理)_第1张图片

 

MFC(菜单,孙鑫C++第六讲笔记整理)_第2张图片

 

这个视频长达3个多小时,把程序分成了三个程序:

具体代码如下:

Menu:

CMainFrame.h

[html]  view plain copy
  1. private:  
  2.     CBitmap cbitmap;  
  3.     CString cstring;  


CMainFrame中的OnCreate:

[html]  view plain copy
  1. //GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION|MF_CHECKED);  
  2.     //GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND|MF_CHECKED);  
  3.   
  4.     //GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_NEW,FALSE);//其中FALSE可以不写,默认的  
  5.     //GetMenu()->GetSubMenu(0)->SetDefaultItem(5,TRUE);//其中分割线也算一个索引,而且一个子菜单中,只能有一个缺省菜单  
  6.   
  7.     /*  
  8.     //CString的成员函数,格式化输出,相当于windows32的wsprintf,输出菜单位图的大小  
  9.     cstring.Format("x=%d,y=%d",::GetSystemMetrics(SM_CXMENUCHECK),::GetSystemMetrics(SM_CYMENUCHECK));  
  10.     this->MessageBox(cstring);//弹出一个box,x=13,y=13  
  11.     */  
  12.       
  13.     //cbitmap.LoadBitmap(MAKEINTRESOURCE(BITMAPID));//cbitmap要设置为成员变量,画位图的时候,位图是13X13的  
  14.     //GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(1,MF_BYPOSITION,&cbitmap,&cbitmap);  
  15.   
  16.     //这里要在CMainFrame构造函数添加一行:m_bAutoMenuEnable =FALSE;这样下面的语句才有效,但是Edith的菜单选项却变成有效的了  
  17.     //GetMenu()->GetSubMenu(0)->EnableMenuItem(2,MF_BYPOSITION|MF_DISABLED|MF_GRAYED);  
  18.   
  19.     /*只是这样是有问题的,有两种解决方法,一种方法是将cmenu设置称为成员变量  
  20.     SetMenu(NULL);//CWnd的成员函数,如果参数为NULL,则移除菜单  
  21.     CMenu cmenu;  
  22.     cmenu.LoadMenu(IDR_MAINFRAME);  
  23.     SetMenu(&cmenu);//把菜单设置回来  
  24.     */  
  25.   
  26.     /*解决方法二,只是按照孙鑫老师方法,只是添加一条cmenu.Detach(),运行,菜单都不见了  
  27.     SetMenu(NULL);  
  28.     CMenu cmenu;  
  29.     cmenu.LoadMenu(IDR_MAINFRAME);  
  30.     HMENU hmenu=cmenu.Detach();  
  31.     CMenu *ccmenu=CMenu::FromHandle(hmenu);  
  32.     SetMenu(ccmenu);  
  33.     */  


CBitMap:

MFC(菜单,孙鑫C++第六讲笔记整理)_第3张图片

CMenu:

一种利用向导生成 浮动菜单

[html]  view plain copy
  1. void CMainFrame::OnRButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.     ClientToScreen(&point);  
  5.     CMenu menu;  
  6.     menu.LoadMenu(MAKEINTRESOURCE(MENUID));  
  7.       
  8.     CMenu *ppopmenu=menu.GetSubMenu(0);  
  9.       
  10.     ppopmenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);  
  11.   
  12.   
  13.     CFrameWnd::OnRButtonDown(nFlags, point);  
  14. }  

 

也可以自己手动设置:

在CXXView中

[html]  view plain copy
  1. void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.   
  5.     ClientToScreen(&point);//客户端转化为屏幕坐标  
  6.     CMenu menu;  
  7.     menu.LoadMenu(MAKEINTRESOURCE(MENUID));  
  8.       
  9.     CMenu *ppopmenu=menu.GetSubMenu(0);  
  10.       
  11.     ppopmenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);  
  12.       
  13.     CView::OnRButtonDown(nFlags, point);  
  14. }  


上面的CMenu是自己添加生成的菜单,

然后去资源头文件,添加三个ID

然后利用向导,可以添加消息响应时间。

设置菜单是否可用:


[html]  view plain copy
  1. void CMenuView::OnUpdateFileNew(CCmdUI* pCmdUI)   
  2. {  
  3.     // TODO: Add your command update UI handler code here  
  4.   
  5.     if(0==pCmdUI->m_nIndex)//这步可有可无,先比较索引  
  6.         pCmdUI->Enable(FALSE);  
  7. }  
  8.   
  9. void CMenuView::OnUpdateEditCut(CCmdUI* pCmdUI)   
  10. {  
  11.     // TODO: Add your command update UI handler code here  
  12.     if(ID_EDIT_CUT==pCmdUI->m_nID)//先比较ID,如果用索引的话,工具栏的图标跟菜单的状态不一定能对上号  
  13.         pCmdUI->Enable();//默认参数是TRUE  
  14. }  


 

下面是程序2 动态添加菜单

Menu2:

CMainFrame中OnCreate:

[html]  view plain copy
  1. //将menu设置成为成员变量  
  2.     menu.CreatePopupMenu();  
  3.     //GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"CSDN");//当第一项参数为MF_POPUP(子菜单)的时候,第二个参数用句柄  
  4.     //GetMenu()->InsertMenu(1,MF_BYPOSITION|MF_POPUP,(UINT)menu.m_hMenu,"CSDN");//标志位可以组合,使用或运算  
  5.     //GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,110,"CSDN");//第一项参数为MF_STRING(子选项)时候,第二参数为整数  
  6.     //GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_BYCOMMAND|MF_STRING,(UINT)m_hWnd,"CSDN");  
  7.   
  8.     //GetMenu()->DeleteMenu(1,MF_BYPOSITION);//删除第二个子菜单  
  9.     //GetMenu()->GetSubMenu(1)->DeleteMenu(ID_EDIT_COPY,MF_BYCOMMAND);//删除第二个子菜单中的复制选项  
  10.   
  11.     GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"CSDN");  
  12.     menu.AppendMenu(MF_STRING,ID_ZICAIDANYI,"zicaidai1");  
  13.     menu.AppendMenu(MF_STRING,ID_ZICAIDANER,"zicaidan2");  
  14.     menu.AppendMenu(MF_STRING,115,"zicaidan3");  


纯手工写菜单,上面已经添加了菜单,下面添加事件。

Resource.h添加MenuID

 

 

然后在下面三个地方添加如下代码:

1MainFrM.h添加事件函数原型

 

2MainFrm.cpp添加消息映射

MFC(菜单,孙鑫C++第六讲笔记整理)_第4张图片

 

3MainFrm.cpp添加事件处理代码

[html]  view plain copy
  1. void CMainFrame::OnZICAIDANYI()  
  2. {  
  3.     MessageBox("你点击了子菜单1");  
  4. }  
  5.   
  6. void CMainFrame::OnZICAIDANER()  
  7. {  
  8.     MessageBox("你点击了子菜单2");  
  9. }  


程序3

创建动态电话本

[html]  view plain copy
  1. void CMenu3View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.       
  5.   
  6.   
  7.   
  8.     //cmenu.CreatePopupMenu();  
  9.     //GetMenu()->GetSubMenu(0)->AppendMenu(MF_POPUP,(UINT)cmenu.m_hMenu,"TEST");  
  10.   
  11.   
  12.     CClientDC ccdc(this);  
  13.       
  14.   
  15.     if(0x0d==nChar)  
  16.     {  
  17.   
  18.         if(0==++m_count)  
  19.         {  
  20.             cmenu.CreatePopupMenu();  
  21.             GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)cmenu.m_hMenu,"PhoneBook");  
  22.             //View类是没有菜单的,是CMainFrame的菜单,CMainFrame是View的父类,所以GetParent();  
  23.               
  24.               
  25.             GetParent()->DrawMenuBar();//拥有Menu的类去调用DrawMenuBar,当Menu有改变的时候,重绘  
  26.         }  
  27.           
  28.         cmenu.AppendMenu(MF_STRING,ID_PHONE1+m_count,cstring.Left(cstring.Find(' ')));  
  29.         cstringarray.Add(cstring);  
  30.         cstring.Empty();  
  31.         Invalidate();  
  32.         SetCaretPos(m_yuandian);  
  33.       
  34.     }  
  35.     else  
  36.     {  
  37.     cstring+=nChar;  
  38.       
  39.     }  
  40.   
  41.   
  42.     CSize cs=ccdc.GetTextExtent(cstring);  
  43.     CPoint cpint(m_yuandian.x+cs.cx,m_yuandian.y);  
  44.       
  45.     SetCaretPos(cpint);  
  46.       
  47.     ccdc.TextOut(m_yuandian.x,m_yuandian.y,cstring);  
  48.       
  49.     CView::OnChar(nChar, nRepCnt, nFlags);  
  50. }  


跟孙鑫老师的有点不一样,有点改动

[html]  view plain copy
  1. void CMenu3View::OnLButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.       
  5.     m_yuandian=point;  
  6.     cstring="";  
  7.     SetCaretPos(point);  
  8.     CView::OnLButtonDown(nFlags, point);  
  9. }  


 

[cpp]  view plain copy
  1. void CMenu3View::OnPhone1()   
  2. {  
  3.     // TODO: Add your command handler code here  
  4.       
  5.     CClientDC ccdc(this);  
  6.     ccdc.TextOut(0,0,cstringarray.GetAt(0));  
  7.           
  8. }  
  9.   
  10. void CMenu3View::OnPhone2()   
  11. {  
  12.     // TODO: Add your command handler code here  
  13.       
  14.     CClientDC ccdc(this);  
  15.     ccdc.TextOut(0,0,cstringarray.GetAt(1));  
  16. }  
  17.   
  18. void CMenu3View::OnPhone3()   
  19. {  
  20.     // TODO: Add your command handler code here  
  21.       
  22.     CClientDC ccdc(this);  
  23.     ccdc.TextOut(0,0,cstringarray.GetAt(2));  
  24. }  
  25.   
  26. void CMenu3View::OnPhone4()   
  27. {  
  28.     // TODO: Add your command handler code here  
  29.       
  30.     CClientDC ccdc(this);  
  31.     ccdc.TextOut(0,0,cstringarray.GetAt(3));  
  32. }  


 

这里孙鑫老师讲了一个技巧,现在Menu资源创建一个临时菜单,ID号跟代码中要添加的ID一致,然后去Resource.h文件添加了四个ID,也就是代码中要添加的菜单选项的ID分别为刚才在Menu资源中菜单选项添加事件,然后在XX.cpp文件中,把消息映射提取到宏的外面,去Menu资源,把临时菜单删了 最后一个知识点是,用CMainFram截获消息:在CMainFram添加一个虚拟函数OnCommand

 

[cpp]  view plain copy
  1. BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)   
  2. {  
  3.     // TODO: Add your specialized code here and/or call the base class  
  4.       
  5.     int MenuCmdid=LOWORD(wParam);  
  6.     CMenu3View *pmenu=(CMenu3View*)GetActiveView();  
  7.     if(MenuCmdid>=ID_PHONE1 && MenuCmdid<ID_PHONE1+pmenu->cstringarray.GetSize())  
  8.     {  
  9.         //MessageBox("test");  
  10.         CClientDC ccdc(pmenu);  
  11.         ccdc.TextOut(0,0,pmenu->cstringarray.GetAt(MenuCmdid-ID_PHONE1));  
  12.         return true;  
  13.     }  
  14.   
  15.   
  16.     return CFrameWnd::OnCommand(wParam, lParam);  
  17. }  

你可能感兴趣的:(MFC(菜单,孙鑫C++第六讲笔记整理))