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

来源:互联网 发布:单片机仿真器 编辑:程序博客网 时间:2024/06/06 17:33

消息分类

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);//第二参数缺省值为FALSECMenu::SetMenuItemBitmapsBOOL 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 defaultCMenu 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 defaultCClientDC 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 classint 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);}


详细程序略






	
				
		
原创粉丝点击