一、首先是对动态菜单的创建,删除,命令响应等操作方法:
菜单的创建是MainFrame类的OnCreate函数中进行的。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar/n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar/n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
// //1.动态添加菜单
// CMenu menu;
// menu.CreateMenu();
// //GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu, "guopeng");
// GetMenu()->InsertMenu(2, MF_POPUP|MF_BYPOSITION, (UINT)menu.m_hMenu, "测试");
// // menu.AppendMenu(MF_STRING,111, "问候");
// menu.AppendMenu(MF_STRING, IDM_HELLO,"问候"); // 在已经在Resources.h中定义了资源ID情况下使用
// menu.AppendMenu(MF_STRING,222, "致谢");
// menu.InsertMenu(1, MF_STRING | MF_BYPOSITION, 333, "插入项1");
// menu.Detach(); //因为创建的menu是局部变量
// // 以下方式可用于对menu或其他的子菜单添加菜单项
// GetMenu()->GetSubMenu(2)->AppendMenu(MF_STRING, 444, "再见");
// GetMenu()->GetSubMenu(2)->InsertMenu(3, MF_BYPOSITION | MF_STRING, 555, "插入项2");
//2.删除菜单
// GetMenu()->DeleteMenu(3, MF_BYPOSITION); // 删除子菜单"查看"
// GetMenu()->GetSubMenu(3)->DeleteMenu(0,MF_BYPOSITION); //删除菜单项就“查看”的"工具栏"
//3.
//为动态添加的菜单添加响应命令,因为不是静态的,在resources的menu视图中看不到菜单项
//也就无法用classWizard创建响应命令函数。必须手工添加
//(1).创建资源ID.文件FileView中找到REsource.h,在其中定义自己的资源ID。eg. #define IDM_HELLO 111
//(2).头文件中添加命令响应函数的原型.在DECLARE_MESSAGE_MAP()前添加afx_msg void OnHello();
//(3).源文件中添加命令映射函数.在END_MESSAGE_MAP()前面添加ON_COMMAND(IDM_HELLO,OnHello) 注意没有分号
//(4).源文件中添加处理函数OnHello(). eg: void CMainFrame::OnHello(){MessageBox("Hello world!");}
return 0;
}
二、简单电话本功能实现。
描述:1、当在窗口中输入一个姓名和电话号码(二者以空格分开)后,回车。在菜单栏中增加一个弹出菜单(只在第一次回车时),并且菜单项中添加姓名,然后再输入姓名电话,可依次加入。
2、当点击电话本菜单中的姓名时,菜单中可显示该姓名和电话。(这种方式能进行的消息响应个数有限)。
输入字符是在view中显示:
CMenu2View::CMenu2View()
{
// TODO: add construction code here
m_nIndex = -1; //手动增加的int变量,记录输入的电话条数
m_strLine = ""; //用于保存输入的字符串
}
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();
//因为菜单栏是属于MainFrame类的,所以要想添加菜单栏,必须先获得MainFrame类的指针
GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)m_menu.m_hMenu,"电话本");
//在windows创建完菜单后再对菜单栏进行操作之后,一定要调用Frame类的重绘菜单栏函数
GetParent()->DrawMenuBar();
}
int i = m_strLine.Find(' '); //返回' ' 的索引值(base 0)
CString str = m_strLine.Left(i); // i截取的字符数
m_menu.AppendMenu(MF_STRING,IDM_PHONE1 + m_nIndex,str); // 添加菜单项
m_strArray.Add(m_strLine); //将输入的字符串添加到字符串数组中
m_strLine.Empty(); // 输入完一次回车后,下次再输入字母时字符串应该已经为空。
Invalidate(); // 将客户区的内容擦除
}
else //按下的不是回车键
{
m_strLine += nChar;
dc.TextOut(0, 0, m_strLine);
}
CView::OnChar(nChar, nRepCnt, nFlags);
}
void CMenu2View::OnPhone1()
{
// TODO: Add your command handler code here
//先随便建一个弹出子菜单并为两个子菜单在view类中添加响应,修改上面增加菜单项的ID号,
//然后删除子菜单,注意要将源文件的映射函数移出到自己增加函数映射的位置,放到END_MESSAGE_MAP()之前
CClientDC dc(this);
dc.TextOut(0, 0, m_strArray.GetAt(0));
}
void CMenu2View::OnPhone2()
{
// TODO: Add your command handler code here
CClientDC dc(this);
dc.TextOut(0, 0, m_strArray.GetAt(1));
}
三。MainFrame类截获本应传给view类处理的OnCommand命令
//手动增加的OnCommand虚函数来截获本来要先传给view类出理的消息
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
int MenuCmdId = LOWORD(wParam); //取wParam的低字节区
CMenu2View * pView = (CMenu2View *)GetActiveView(); //CMenu2View类要包含在mainFrame类的源文件中
if (MenuCmdId >= IDM_PHONE1 && MenuCmdId < IDM_PHONE1 + pView->m_strArray.GetSize())
{
// MessageBox("testing!");
CClientDC dc(pView);
dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId - IDM_PHONE1));
}
return CFrameWnd::OnCommand(wParam, lParam);
}