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

 

 

 

这个视频长达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);
}


 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值