资源视图中打开菜单,在需要添加响应的菜单项上右击属性将Popup改为false,右键添加响应函数,选择响应函数所在的类即可,编辑响应函数。
4个类的消息响应优先次序分别是:1.View;2.CDOC;3.CMainFrame.4.CWinAPP.
View类和CMainFrame继承自CWIND所以可以直接调用MessageBox(“…”)函数,CDOC和CWinAPP只能用一般的AfxMessageBox(_T("doc clicked"))函数。
标准消息(以WM_开头的消息,但不包括ON_COMMAND),如WM_Paint;b;命令消息 ON_COMMAND(IDM_PHONE1, OnPhone1),菜单和工具栏的消息。c.通告消息:按钮,对话框,列表框发出的消息。
CCmdTarget只能接受命令消息,如文档类和APP类只能接受命令消息,不能接受标准消息。而从CCmdTarget派生的CWnd可以接收命令消息,也可以接受标准消息。通告消息都可以接收。
在CMainFrame::OnCreate函数下:
GetMenu(); CWnd的成员函数,返回整个菜单栏的指针。
GetMenu()->GetSubMenu(0); 获取子菜单,参数为子菜单索引,从0开始
GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION|MF_CHECKED); /通过位置索引设置标记
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND|MF_CHECKED); //通过菜单项的ID进行索引设置标记
在VS2010中,由于CMainFrame继承至CFrameWndEx会导致无法像VC6.0一样使用GetMenu()等函数,所以这时在建立工程的时候就应该选择为:
第一步:项目标准: MFC标准
视觉样式和颜色:windows 本机/默认
第五步:命令栏:使用经典菜单
这样就和VC6.0中的菜单一样了
CMenu::SetDefaultItem(UINT ,BOOL); //bool为false则UINT为ID表示,true为地址索引表示。
GetMenu()->GetSubMenu(0)->SetDefaultItem(1,true);将文件-打开设置为缺省项。
确定菜单的索引号,注意从0开始,分隔符也算数。
一个子菜单只能有一个缺省菜单。
CMenu::SetMenuItemBitmaps(UINT nposition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked);
nFlags: MF_BYPOSITION 和MF_BYCOMMAND位置索引和ID索引。
pBmpUnchecked: 没有选中时的位图
pBmpChecked: 选中时的位图
具体操作:
先通过GetSystemMetrics()函数获取菜单图标大小,按这个大小制作位图:
CString str;
str.Format(_T("x=%d,y=%d"),GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK));
MessageBox(str); //显示出来宽高,13*13的,然后制作13*13的位图
然后CMainFrame中添加成员变量:m_bitmap
m_bitmap.LoadBitmapW (IDB_BITMAP1);
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);
CMenu::EnableMenuItem(UINT nIDEnableItem, UINT nEnable);
具体操作:
在CMainFrame构造函数中设置m_bAutoMenuEnable=false;从而EnableMenuItem可以起作用,然后在OnCreate函数中:
GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_BYPOSITION|MF_DISABLED|MF_GRAYED); //屏蔽打开菜单项并使其变灰
CMenu::SetMenu(CMenu* pMenu); //pMenu为NULL时为当前菜单被移走
SetMenu(NULL); //取消当前菜单
CMenu menu; //定义成成员变量,或紧接着Detach函数
menu.LoadMenuW(IDR_MAINFRAME); //重新加载菜单
SetMenu(&menu);
menu.Detach();
在CMainFrame构造函数中取消设置m_bAutoMenuEnable=false;选择采用命令更新机制。可以看到编辑子菜单下的撤销、剪切、复制、粘贴等菜单项都不能使用了。
添加时间处理函数,其中消息类型选择UPDATE_COMMAND_UI,创建相应函数:
void CMainFrame::OnUpdateEditCut(CCmdUI *pCmdUI)
该函数传递了一个CCmdUI类的指针。在该相应函数中:
pCmdUI->Enable(); //这样剪切键就可以使用了, Enable的默认参数为true
pCmdUI->Enable(FALSE); //使菜单项无法使用
在执行Enable函数之前可以先进行判断,判断pCmdUI是否指向当前菜单项:
if(2==pCmdUI->m_nIndex) //通过地址判断,这是菜单项的剪切可用,工具栏中剪切依然不可用
pCmdUI->Enable();
或通过ID号索引:
if(ID_Edit_Cut==pCmdUI->m_nID) //通过ID号索引,菜单项和工具栏中的都可用
pCmdUI->Enable();
Project->Add to Project->component and controls在vs2010中找不到,手动创建。
具体操作:
资源中新建一个菜单
CMenuView类中添加右键响应函数OnRButtonDown
CMenu menu;
menu.LoadMenu(IDR_Popup);
CMenu *pPopup=menu.GetSubMenu(0); //获取子菜单,只有一个子菜单
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
this); //point是屏幕坐标,所以要先ClientToScreen将客户区坐标转换为屏幕坐标
由于TrackPopupMenu调用的是this指针,因此弹出菜单中的菜单项的响应只能由view执行,框架类不能响应,为了使框架类也能指向响应操作,需将this换为其父窗口的指针GetParent()。
1函数原型:BOOL AppendMenu(hMenu hMenu,UINT uFlags,UINT uIDNewltem,LPCTSTR lpNewltem);
将被修改的菜单条、下拉式菜单、子菜单、或快捷菜单的句柄。
控制新菜单项的外观和性能的标志。此参数可以是备注里所列值的组合。
指定新菜单项的标识符,或者当uFlags设置为MF_POPUP时,表示下拉式菜单或子菜单的句柄。
指定新菜单项的内容。此参数的含义取决于参数uFlags是否包含MF_BITMAP, MF_OWNERDRAW或MF_STRING标志,如下所示:
含有位图句柄。MF_STRING:以`\O’结束的字符串的指针。
含有被应用程序应用的32位值,可以保留与菜单项有关的附加数据。当菜单被创建或其外观被修改时,此值在消息WM_MEASURE或WM_DRAWITEM的参数IParam指向的结构,成员itemData里。
返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
备注:一旦菜单被修改,无论它是否在显示窗口里,应用程序必须调用函数DrawMenuBar。
为了使键盘加速键能控制位留或自己绘制的菜单项,菜单的拥有者必须处理WM_MENUCHAR消息。
参见自绘制菜单和WM_MENUCHAR消息。
2函数原型:HMENU CreatePopupMenu(VOID)
函数功能:该函数创建一个下拉式菜单、子菜单或快捷菜单。此菜单最初是空的,但可用函数InsertMenultem来插入或追加菜单项。也可用函数InsertMenu来插人菜单项,用AppendMenu来追加菜单项。
参数:无。
返回值:如果函数调用成功,返回值是新创建菜单的句柄。如果函数调用失败,返回值是NULL。若想获得更多的错误信息,请调用GetLastError函数。
3 BOOL InsertMenu(HMENU hMenu,UINt uPosition,UINT uFlags,UINT uIDNewltem,LPCTSTR lpNewltem)
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("Mybole"));
menu.Detach();
< xmlnamespace prefix ="v" ns ="urn:schemas-microsoft-com:vml" />
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); //删除打开菜单项
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!");
}
1 view类中处理WM_Char消息。
void CMenu2View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(0x0d==nChar) //回车
{
if(0==++m_nIndex) //如果第一次按回车,则创建菜单
{
m_menu.CreatePopupMenu ();
GetParent()->GetMenu()->AppendMenuW(MF_POPUP, (UINT)m_menu.m_hMenu, _T("PhoneBook"));
//菜单属于框架类所以要GetParent()->GetMenu()来获取
GetParent()->DrawMenuBar();
//重绘菜单,否则不显示,又因为菜单属于框架类所以要GetParent()->
}
m_menu.AppendMenuW (MF_STRING, IDM_PHONE1+m_nIndex, m_strLine.Left (m_strLine.Find (' '))); //以字符串空格前的字符为名创建菜单项
m_strArray.Add (m_strLine); //m_strArray为CstringArray类型的成员变量,存储CString
m_strLine.Empty (); //清空字符串
Invalidate(); //窗口背景被擦除
}
else
{
m_strLine+=char(nChar);
dc.TextOut(0,0,m_strLine);
}
CView::OnChar(nChar, nRepCnt, nFlags);
}
2 添加菜单项的消息处理函数
Menu2View.h 中加入:
afx_msg void OnPhone1();
afx_msg void OnPhone2();
afx_msg void OnPhone3();
Menu2View.cpp中加入:
ON_COMMAND(IDM_PHONE1, &CMenu2View::OnPhone1)
ON_COMMAND(IDM_PHONE2, &CMenu2View::OnPhone2)
ON_COMMAND(IDM_PHONE3, &CMenu2View::OnPhone3)
void CMenu2View::OnPhone1()
{
CClientDC dc(this);
dc.TextOutW (0,0,m_strArray.GetAt (0)); //取出m_strArray中数据
}
CMainFrame中增加虚函数:
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: 在此添加专用代码和或调用基类
int MenuCmdId=LOWORD(wParam);
CMenu2View *pView=(CMenu2View*)GetActiveView();
// GetActiveView()为CMainFrame类的成员函数,获取view类指针
if(MenuCmdId>=IDM_PHONE1&&MenuCmdId
{
//MessageBox(_T("test"));
CClientDC dc(pView); //用View类指针创建dc
dc.TextOutW (0,0,pView->m_strArray .GetAt (MenuCmdId-IDM_PHONE1));
return true;
}
return CFrameWnd::OnCommand(wParam, lParam);
}
注意要增加两个头文件:
#include "Menu2Doc.h"
#include "Menu2View.h"
为了加深理解可以看一看“WM_COMMAND消息路由”。