孙鑫VC++视频学习笔记(第六课 菜单的工作原理及编写控件)

消息分类

1.标准消息:

除WM_COMMAND之外,所有以 WM_ 开头的消息。

从CWnd派生的类,都可以接收到这类消息

2.命令消息

来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中通过消息的wParam参数识别

从CCmdTarget派生的类,都可以接收到这类消息。

3通告消息

由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是想器父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现

从CCmdTarget派生的类,都可以接收到这类消息

                    

MFC类的结构层次图



菜单的索引是从0开始,子菜单中的菜单项之间的分割符也算一位。


CWnd::GetMenu()

CMenu* GetMenu() const;  获得菜单栏的指针


CMenu::GetSubMenu()  获得一个菜单项的指针

CMenu* GetSubMenu(int nPos) const


CMenu::CheckMenuItem()  在一个菜单项打一个标记

UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck);

当 nCheck=MF_BYCOMMAND

 第一个参数代表的是菜单项的ID号(ID_

当 nCheck=MF_BYPOSITION

第一个参数代表的是菜单项的索引号(0,1,2...)


示例程序

GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED);
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_CHECKED);
获得一个子菜单指针,再获取索引号为0的菜单项指针 ,标记索引号为0 (ID号为ID_FILE_NEW)的菜单项

GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);
GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN);//第二参数缺省值为FALSE
CMenu::SetMenuItemBitmaps
BOOL SetMenuItemBitmaps(
   UINT nPosition,
   UINT nFlags,//这两个参数与前面的一样
   const CBitmap* pBmpUnchecked,//没有选中用这个位图
   const CBitmap* pBmpChecked //选中就用这个位图
);
创建一个图形标识菜单,在资源视图中添加一个位图(IDB_BITMAP)
示例程序

CBitmap m_bitmap;//用建立类向导ClassWizard添加类的成员变量
m_bitmap.LoadBitmap(IDB_BITMAP);
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);
//当背景色为白色的位图可能看不到效果,位图尺寸太大无法显示完整
可用
CString str;
str.Format("x=%d,y=%d",::GetSystemMetrics(SM_CXMENUCHECK),
	::GetSystemMetrics(SM_CYMENUCHECK);
获得缺省的标识位图的尺寸大小(单位:像素)


将禁用某一个菜单项项,使其变灰

GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_POSITION | MF_DISABLED | MF_GRAYED);
//程序效果无效,结果还是可以打开该菜单项
查看MSDN
// The code fragment below shows how to disable (and gray out) the File\New menu item.// NOTE: m_bAutoMenuEnable is set to FALSE in the constructor of CMainFrame so no ON_UPDATE_COMMAND_UI or ON_COMMAND handlers are needed, and CMenu::EnableMenuItem() will work as expected.
在类的构造函数中可以将m_bAutoMenuEnable=FALSE

加载自己的菜单资源
SetMenu(NULL);
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
menu.Detach();//当menu为类的成员变量时可不用,当为本地变量时要调用,不然会发生错误


命令更新

 菜单项状态的维护是依赖与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处理程序仅应用于弹出式菜单项上的项目,不能应用与永久显示的顶级菜单项目


添加右键弹出菜单功能

VC6编辑器

工程-》添加到工程-》Components and Controls Gallery-》Visual C++ Components-》Pop-up Menu

提示增加到哪个类当中,不要选择框架类,框架类接受不到鼠标消息,可以增加到View类当中!

MFC会在我们的工程当中增加一个菜单资源,和View类中添加一个OnContextMenu函数


手动添加

调用TrackPopupMenu

CMenu::TrackPopupMenu
BOOL TrackPopupMenu(
   UINT nFlags,
   int x,
   int y,
   CWnd* pWnd,
   LPCRECT lpRect = 0
);


示例代码

利用ClassWizard添加右键鼠标消息

void CMenu1View::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CMenu menu;
	menu.LoadMenu(IDR_MENU1);//加载自定义的菜单资源
	CMenu *pPopup=menu.GetSubMenu(0); //获得菜单项指针
	ClientToScreen(&point);//转换point坐标,将客户区坐标转换为屏幕坐标

	pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
			GetParent()/*this*/);
                      //如果为this就表示该弹出窗口拥有者为View类,因此只能是View类为我们的弹出菜单中的菜单项进行命令响应
 	              //如果想要框架类也能为该弹出猜中的菜单项进行命令响应,可以将最后一个参数this改为GetParent()获得框架类的指针
	
	CView::OnRButtonDown(nFlags, point);
}


动态添加菜单

CMenu::CreatePopupMenu     创建一个空的弹出菜单
CMenu::AppendMenu  添加一个新的菜单项
	
        CMenu menu;
	menu.CreatePopupMenu();
	//GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,_T("WinSun"));
	GetMenu()->InsertMenu(2,MF_BYPOSITION | MF_POPUP,(UINT)menu.m_hMenu,_T("WinSun"));


	menu.AppendMenu(MF_STRING,111,_T("Hello"));
	menu.AppendMenu(MF_STRING,112,_T("Weixin"));
	menu.AppendMenu(MF_STRING,113,_T("My"));
	menu.Detach();
        GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,_T("WELCOM"));
	GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_BYCOMMAND | MF_STRING,115,_T("小豆"));//插入


	GetMenu()->DeleteMenu(1,MF_BYPOSITION);//删除
	GetMenu()->GetSubMenu(0)->DeleteMenu(2,MF_BYPOSITION);

我们可以手动添加对菜单项的响应,一可以通过ClassWizard来添加。


课程实验设计 -------电话本程序


CString m_strLine;

int m_nIndex;

CStringArray m_strArray;

CMenu m_menu;

void CMenu2View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	CClientDC dc(this);
	if(0x0d==nChar)
	{
		if(0==++m_nIndex)
		{
			m_menu.CreatePopupMenu();
			GetParent()->GetMenu()->AppendMenu(MF_POPUP,
					(UINT)m_menu.m_hMenu,_T("PhonBook"));//在View类中获得框架类的指针使用GetParent
			GetParent()->DrawMenuBar();//马上更新菜单栏

		}
		m_menu.AppendMenu(MF_STRING,IDM_PHONE1+m_nIndex,m_strLine.Left(m_strLine.Find(' ')));
		m_strArray.Add(m_strLine);
		m_strLine.Empty();
		Invalidate();//缺省为TRUE,客户区更新
	}
	else
	{
		m_strLine+=nChar;
		dc.TextOut(0,0,m_strLine);

	}
	
	CView::OnChar(nChar, nRepCnt, nFlags);
}

在在框架类CMainFrame中利用ClassWizard添加虚函数OnCommand()来截获消息并处理

BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) 
{
	// TODO: Add your specialized code here and/or call the base class
	int MenuCmdID=LOWORD(wParam); //获得低字节
	CMenu2View *pView=(CMenu2View*)GetActiveView();//获得当前视类的指针,从得到我们所需要的其中的m_strArray数据
	if(MenuCmdID>=IDM_PHONE1 && MenuCmdID<=IDM_PHONE1+pView->m_strArray.GetSize());
	{
		//MessageBox("xiaodou");
		CClientDC dc(pView);
		dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdID-IDM_PHONE1));
		return TRUE;
	}
	
	return CFrameWnd::OnCommand(wParam, lParam);
}


详细程序略









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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值