VC++深入详解笔记(2)之菜单

本文目的:菜单命令的路由、菜单的的基本操作、右键菜单的创建及动态菜单的创建。

一、Windows消息的分类

1、标准消息:除去WM_COMMAND之外的所有以WM_开头的消息都是标准消息。从CWnd派生的类可以接受到这类消息。

2、命令消息:来自菜单、加速键或者工具栏按钮的消息。这类消息以WM_COMMAND形式呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过wParam参数识别。从CCmdTarget派生的类都可以接收到这类消息。(注:CWnd也是派生自CCmdTarget类的)

3、通告消息:由控件产生的消息,目的是向父窗口通知事件的发生。其形式与接收类与命令消息相同。

二、菜单命令的路由

程序对菜单命令响应的顺序为:视图类->文档类->框架类->应用程序类。

具体路由顺序为:框架类接收到菜单命令消息后,将消息交给它的子窗口即视图类;视图类首先对消息进行处理,若响应了,则进行该消息的处理,消息路由结束,若消息映射机制检查没有响应该消息的响应函数,则将消息交给文档类;同样,文档类判断是否对该消息进行了响应,若没有 它会将这个消息交还给视图类,视图类又交给框架类;这个时候框架类再查看自己是否对这个消息进行了响应,若没有,则将这个菜单消息交给应用程序类进行处理。

三、基本菜单操作

①CMenu * GetMenu() const 获取指向菜单栏的指针,CMenu类是一个MFC类,提供了一些与菜单操作相关的成员函数。

②CMenu * GetsubMenu(int nPos) const 获取一个菜单的子菜单,nPos为子菜单的索引号,②返回的CMenu * 与①返回的CMenu* 所指向的对象是不同的。

③UINT CheckMenuItem(UINT  nIDCheckItem, UINT  nCheck) ,该函数具体用法参见MSDN。

④BOOL SetDefaultItem(UINT uItem, BOOL fByPos = FALSE)  将该子菜单的一个菜单项设置为默认菜单项(粗体显示)。

③和④两个函数的第一个参数均有第二个参数决定。

⑤SetMenuItemBitmaps(...) 设置图形标记菜单。

⑥int GetSystemMetrics(int nIndex) 可以得到图形标记菜单上显示的位图的尺寸。从而我们可以在资源视图中对菜单进行响应的调整。

⑦UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable) 设置菜单项的状态:能够使用、禁用、变灰等。要想该函数能正常工作,需要在CMainFrame 类中的构造函数中将成员变量m_bAutoMenuEnable设置为FALSE,这是MFC提供的一种命令更新机制,该机制去判断各个菜单的状态。设置为FALSE后,更新将由我们自己完成。

⑧SetMenu(CMenu * pMenu) 移除菜单,CMenu类中的LoadMenu()函数加载菜单。

⑨CMenu类中的Detach()函数将菜单句柄与这个菜单对象分离。

四、右键菜单

又称快捷菜单或上下菜单。

方法一:通过添加组件的方式添加Popup菜单组件。

方法二:手动添加

1、 在资源视图中创建要显示的右键菜单;

2、为视图类添加鼠标右键点下的消息响应函数,在该函数里进行处理。CMenu menu; menu.LoadMenu(IDR_MENU1); CMenu * pPpoup = menu.GetSubMenu(0);

ClientToScreen(&point); pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,point.y,this);

五、动态菜单

即在程序运行过程中创建菜单。一种是针对弹出菜单的动态操作,一种是针对菜单项的动态操作。

⑩BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL);把一个菜单项添加到一个制定菜单项目的末尾。

相关函数有: CreateMenu(),InsertMenu(),DeleteMenu()。

关于OnPhone的消息响应函数,我们可以先在资源视图中相应位置建立菜单,并生成消息响应函数,注意将BEGIN_MESSAGE_MAP 下的OnPhone 映射拷贝出注释宏,然后删掉资源视图中我们刚建立的菜单,但OnPhone的消息响应保留了下来,这为我们下面的操作提供了很大便利。

最后贴上一段电话本示例OnChar代码

void CChapter6_2View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	CClientDC dc(this);
	if(13 == nChar)
	{
		if( 0 == ++m_nIndex)
		{
			m_menu.CreatePopupMenu();
			GetParent()->GetMenu()->AppendMenu(MF_POPUP,
				(UINT)m_menu.m_hMenu,"PhoneBook");
			GetParent()->DrawMenuBar();

		}
		m_menu.AppendMenu(MF_STRING,IDM_PHONE1+m_nIndex,
			m_str.Left(m_str.Find(' ')));
		m_strArray.Add(m_str);
		m_str.Empty();
		Invalidate();
	}
	else
	{
		m_str += nChar;
		dc.TextOut(0,0,m_str);
	}	
	CView::OnChar(nChar, nRepCnt, nFlags);
}

注意在响应的OnPhone 函数中添加以下代码

	CClientDC dc(this);
	Invalidate();<span style="white-space:pre">				</span>//刷新显示的数据
	UpdateWindow();
	dc.TextOut(0,0,m_strArray.GetAt(0));   //索引号可以改变

微笑除此我们还可以通过框架类来截获菜单命令消息,通过重写OnCommand()函数来实现,它是个虚函数,你懂的。

BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) 
{
	// TODO: Add your specialized code here and/or call the base class
	int MenuCmdId = LOWORD(wParam);
	CChapter6_2View * pView = (CChapter6_2View*)GetActiveView();
	if(MenuCmdId >= IDM_PHONE1 && MenuCmdId < IDM_PHONE1
		+ pView->m_strArray.GetSize())
	{
		Invalidate();
		UpdateWindow();
		//MessageBox("test"); 
		CClientDC dc(pView);
		dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId-IDM_PHONE1));
		return TRUE;
	}
 	return CFrameWnd::OnCommand(wParam, lParam);
}



  

  


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值