一、菜单
1. 新建一个单文档SDI工程1MiniCAD,在原菜单右侧添加“绘图”子菜单:
菜单项名 | 热键 | 加速键(快捷键) | 状态栏提示 | 工具栏图标提示 |
普通模式 | (&M) | \t Ctrl+M | 退出绘图模式 | \n普通模式 |
画线 | (&L) | \t Ctrl+L | 进入画线模式 | \n画线 |
实现上述菜单功能。
2. 菜单消息传递顺序:View类àDoc类àCMainFrame类àApp类。菜单消息一旦在其中一个类中响应,则不再在其它类中查找响应函数。在上述菜单的”选择颜色”下方添加一个Test项进行测试。
3. 概念:菜单栏、菜单、子菜单、菜单项、分隔条(Separator)
菜单栏从左到右是从0开始的索引,菜单项由上至下也是从0开始的索引,访问子菜单和菜单项均通过其索引或标识ID进行。在计算菜单项的索引的时候,分隔栏Separator也要计算在内。
相关重要函数:
CMenu* GetMenu() ; //得到窗口菜单栏对象指针。
CMenu* GetSubMenu(4) ;/获得指向弹出菜单对象指针
UINT CheckMenuItem(); //在菜单项前面打勾
BOOL SetDefaultItem(); //使菜单项变粗变黑
UINT EnableMenuItem();//使菜单项有效,无效,或变灰。
BOOL SetMenuItemBitmaps( );//设置位图菜单。
BOOL SetMenu( CMenu* pMenu );//在当前窗口上设置新菜单或移除菜单。
HMENU Detach( ); //解除捆绑
示例:
a. 在CMiniCADView::OnCreate()中,使菜单项“普通模式”成为打勾状态:
GetParent()->GetMenu()->GetSubMenu(4)->
CheckMenuItem(ID_DRAW_NONE, MF_BYCOMMAND | MF_CHECKED);
b. 在CMainFrame::OnCreate()中,使菜单项“普通模式”成为默认菜单:
m_bAutoMenuEnable = FALSE;
GetMenu()->GetSubMenu(4)->SetDefaultItem(ID_DRAW_NONE);
c. 在CMainFrame::OnCreate()中,使菜单项“打印预览”变成灰色,不可用状态:
//禁止“打印预览”菜单项:
//EnableMenuItem()需要将CFrameWnd::m_bAutomenuEnable设置为FALSE,
//如果该数据成员为TRUE(缺省值),工作框将自动地禁止没有实现
//ON_COMMAND或者ON_UPDATE_COMMAND_UI的菜单项。
m_bAutoMenuEnable = FALSE;
GetMenu()->GetSubMenu(0)->EnableMenuItem(6,
MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
d. 在CMainFrame::OnCreate()中,给Save As菜单项增加图标:
CString str;
str.Format("x=%d,y=%d", GetSystemMetrics(SM_CXMENUCHECK),
GetSystemMetrics(SM_CYMENUCHECK));
MessageBox(str);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(3, MF_BYPOSITION, &bitmap, &bitmap);
bitmap.Detach(); //使HBITMAP和CBitmap解除捆绑,否则会使SetMenuItemBitmaps失效。
说明:int GetSystemMetrics()获取系统信息度量。可以用它来获取菜单标题的尺寸从而设置位图标题菜单中位图的大小。
e. 在CMainFrame::OnCreate()中,移除/增加菜单
CMenu *pMenu = this->GetMenu();
this->SetMenu(NULL); //移除菜单
this->SetMenu(pMenu); //增加菜单
4. 在资源管理器中设置加速键。然后在CApp类的InitInstance()中加载快捷键,使定义的Ctrl+M等起作用:HACCEL hAccelTable =
LoadAccelerators(theApp.m_hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
6. 使用 TrackPopupMenu 函数,添加右键弹出菜单:
1)用资源管理器添加一个菜单资源,也可以利用主菜单中的某个子菜单作为要弹出的菜单。
2)在鼠标右键消息响应函数中,加载菜单资源,并获得要显示的子菜单指针,并用该指针调用TrackPopupMenu函数便完成任务(但要注意:鼠标响应函数传进来的坐标是客户区坐标,而TrackPopupMenu函数中使用的是屏幕坐标,在调用TrackPopupMenu前要调用ClientToScreen客户区坐标到屏幕坐标的转换),如:
void CMiniCADView::OnRButtonUp(UINT nFlags, CPoint point)
{
//CMenu menu;
//menu.LoadMenu(IDR_MAINFRAME);
//CMenu *pPopup=menu.GetSubMenu(4);
//ClientToScreen(&point);
//pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, GetParent());
CView::OnRButtonUp(nFlags, point);
}
3) 可用WM_CONTEXTMENU消息替换在鼠标右键消息响应函数来完成TrackPopupMenu的工作。如:
void CMiniCADView::OnContextMenu(CWnd* pWnd, CPoint point)
{
//CMenu menu;
//menu.LoadMenu(IDR_MAINFRAME);
//CMenu *pPopup = menu.GetSubMenu(4);
//pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, GetParent());
GetParent()->GetMenu()->GetSubMenu(4)->TrackPopupMenu(
TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, GetParent());
}
1. 动态菜单编程:
l 创建动态菜单。常用函数有:
CMenu::CreatePopupMenu //创建一个Popup菜单,如“电话本”
CMenu::DrawMenuBar //绘制菜单
CMenu::AppendMenu //给菜单增加一项,查MSDN,注意nFlags参数的用法
如:
GetParent()->GetMenu()->AppendMenu(MF_POPUP, (UINT)m_menu.m_hMenu, "电话本");
m_menu.AppendMenu(MF_STRING, m_nIndex + IDM_PHONE1, "张三");
l 为动态菜单添加响应函数:(注意,不是自定义消息)
首先在resource.h中定义菜单ID,如:
#define IDM_PHONE1 32777
#define IDM_PHONE2 32778
第二,消息映射,如:
ON_COMMAND(IDM_PHONE1, OnPhone1)
ON_COMMAND(IDM_PHONE2, OnPhone2)
第三,定义菜单响应函数,如:
afx_msg void OnPhone1();
afx_msg void OnPhone2();
第四,实现菜单响应函数。
示例:
void CMiniCADView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
if (nChar != 13) //用户还没有按下回车键
{
CClientDC dc(this);
m_strLine += (char)nChar;
dc.TextOut(10, 10, m_strLine); //显示用户输入的电话,如“张三13902933223”
}
else //用户按下了回车键
{
m_nIndex++; //m_nIndex初值为-1
if (0 == m_nIndex) //说明“电话本”菜单项还没有创建,则创建之
{
m_menu.CreatePopupMenu();
GetParent()->GetMenu()->AppendMenu(MF_POPUP, (UINT)m_menu.m_hMenu, "电话本");
GetParent()->DrawMenuBar(); //绘制刚创建的弹出菜单“电话本”
}
//增加“张三13902933223”中的“张三”到菜单“电话本”下面.
m_menu.AppendMenu(MF_STRING, m_nIndex + IDM_PHONE1, m_strLine.Left(m_strLine.Find(' ')));
//将记录保存进字符串数组
m_strArray.Add(m_strLine); //CStringArray
//清空, 清屏, 为输入下一个人的号码做好准备
m_strLine = "";
this->Invalidate(); //清屏
}
CView::OnChar(nChar, nRepCnt, nFlags);
}
void CMiniCADView::OnPhone1()
{
CClientDC dc(this);
dc.TextOut(10, 10, m_strArray[0]);
}
void CMiniCADView::OnPhone2()
{
CClientDC dc(this);
dc.TextOut(10, 10, m_strArray[1]);
}
文章出自:www.rjpx.net