您的位置:首页 > 编程语言 > C语言/C++

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

2011-12-09 16:01 417 查看
消息分类

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);
}


详细程序略





                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐