4. 菜单

4.1 弹出菜单

本节主要讲解如何在主对话框的指定区域内通过鼠标右击来弹出一个菜单选项。最终效果图如图4.1。

如图4.1鼠标只能在指定区域(图中深色区域)内右击时弹出菜单,在指定区域外点击时不执行创建菜单操作。具体操作步骤如下:

(1) 首先在指定区域响应鼠标右击消息,需要在主对话框类中添加消息句柄WM_RBUTTONUP,并在该消息响应函数void CFDlg::OnRButtonUp(UINT nFlags, CPoint point)中进行坐标判断,示例代码如下:

void CFDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
RECT myrc;//指定窗口区域
RECT wndrc;//主对话框窗口区域
RECT myrc_to_wndrc;//指定区域相对主窗口坐标
int pt_to_wndrcX;//光标X位置相对主窗口坐标
int pt_to_wndrcY;//光标Y位置相对主窗口坐标
CPoint pt_to_screen(point);//建立一个相对屏幕坐标系下的光标位置坐标
//获取指定区域的窗口指针
CWnd* mywnd = GetDlgItem(IDC_BITMAPAREA);
//获取指定窗口的客户坐标
mywnd->GetClientRect(&myrc);
//指定区域相对屏幕坐标系下的坐标
mywnd->ClientToScreen(&myrc);
//获取主窗口的客户区域坐标
GetClientRect(&wndrc);
//主窗口的客户区域相对屏幕坐标系下的坐标
ClientToScreen(&wndrc);
//光标位置相对屏幕坐标下的坐标
ClientToScreen(&pt_to_screen);
//计算指定窗口区域和光标位置相对主窗口客户区域的坐标
myrc_to_wndrc.left = myrc.left - wndrc.left;
myrc_to_wndrc.right = myrc.right - wndrc.left;
myrc_to_wndrc.top = myrc.top - wndrc.top;
myrc_to_wndrc.bottom = myrc.bottom - wndrc.top;
pt_to_wndrcX = pt_to_screen.x - wndrc.left;
pt_to_wndrcY = pt_to_screen.y - wndrc.top; if ( pt_to_wndrcX > myrc_to_wndrc.left && pt_to_wndrcX < myrc_to_wndrc.right &&
pt_to_wndrcY > myrc_to_wndrc.top && pt_to_wndrcY < myrc_to_wndrc.bottom)
{
//在指定区域进行鼠标右击消息响应操作,本节是创建弹出式菜单
}
CDialog::OnRButtonUp(nFlags, point);
}

(2) 其次创建弹出式菜单,示例代码如下:

CMenu mymenu;
if (mymenu.CreatePopupMenu())
{
//定义两条菜单项显示的字符串,其中‘&’比较有用,用于对弹出菜单通过指定键盘字符来响应
CString strFSR("第 1 条(&F)");
CString strWH("第 2 条(&S)");
//增加第1条菜单项,函数的第二个参数在Resource.h文件已经定义:
// #define IDM_FSRMENU 0x0020
// #define IDM_WHMENU 0x0030
mymenu.AppendMenu(MF_STRING, IDM_FSRMENU, strFSR);
//添加一条分割线
mymenu.AppendMenu(MF_SEPARATOR);
mymenu.AppendMenu(MF_STRING, IDM_WHMENU, strWH );
//在指定位置显示一个弹出式菜单
mymenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, pt_to_screen.x, pt_to_screen.y,this);
}

(3) 查看MSDN对CMenu::TrackPopupMenu的解释可知,TrackPopupMenu的第4个参数表示哪个窗口拥有这个菜单,该窗口处理菜单的WM_COMMAND消息。因此还需要添加对菜单条目的响应处理,示例代码如下:

BOOL CFDlg::OnCommand(WPARAM wParam, LPARAM lParam)
{
//添加菜单条目的命令消息代码
if (wParam = = IDM_FSRMENU)
{
MessageBox("选择第 1 条菜单选项");
}
else if (wParam = = IDM_WHMENU)
{
MessageBox("选择第 2 条菜单选项");
}
else
{
CDialog::OnCommand(wParam,lParam);
}
return TRUE;
}

此外还需要对OnCommand函数进行申明:

virtual BOOL OnCommand( WPARAM wParam,  LPARAM lParam );系统框架调用该函数。

最后,结合图文方式介绍几个菜单条目操作:

(1) 菜单条目前添加位图,示例代码如下:

CString strFSR("第 1 条(&F)");
CString strWH("第 2 条(&S)");
// 增加第1条菜单条目,函数的第一个参数选择了MF_CHECKED,表示该菜单条目前有一个选中位图
//(形如“√”),如图4.2的第1条菜单条目所示
mymenu.AppendMenu(MF_STRING | MF_CHECKED , IDM_FSRMENU, strFSR );
mymenu.AppendMenu(MF_SEPARATOR);//添加分割线
mymenu.AppendMenu(MF_STRING, IDM_WHMENU, strWH );//添加第2条菜单条目
//添加第3条菜单条目,函数的第1个参数选择了MF_CHECKED
mymenu.AppendMenu(MF_CHECKED, 0x0040,"第 3 条(&T)");
// 为第3条菜单条目前增加一个位图,函数的第3、4参数分别表示当菜单未选中时使用的位图和菜单选
// 中时所用的位图。因此首先之前已经创建了两幅CBitmap对象。如图4.2所示,第3条菜单的状态是选
// 中,因此前面的“√”消失,取而代之的是一幅位图。而当第3条菜单条目是未被选中(AppendMenu
// 第1个参数是MF_UNCHECKED)那么此时该条目前显示的是未选中状态的位图,如图4.3。
mymenu.SetMenuItemBitmaps(0x0040,MF_BYCOMMAND,&uncheck_map,&check_map);
mymenu.AppendMenu(MF_STRING, 0x0050,"第 4 条(&D)");//添加第4条菜单条目

实现效果如图4.2和4.3:

(2) 创建层叠菜单,效果图如图4.4:

示例代码如下:

CMenu mymenu;
CMenu newmenu;//--
//创建一个层叠菜单,在后续操作时将其关联到主菜单的指定条目上
newmenu.CreatePopupMenu();
newmenu.AppendMenu(MF_UNCHECKED,0x0060,"层叠1");
newmenu.AppendMenu(MF_CHECKED,0x0070,"层叠2");
newmenu.AppendMenu(MF_STRING,0x0080,"层叠3");
CBitmap check_map;
CBitmap uncheck_map;
if (mymenu.CreatePopupMenu())
{
check_map.LoadBitmap(IDB_BITMAP3);
uncheck_map.LoadBitmap(IDB_BITMAP4);
CString strFSR("第 1 条(&F)");
CString strWH("第 2 条(&S)");
mymenu.AppendMenu(MF_STRING | MF_CHECKED , IDM_FSRMENU, strFSR );
mymenu.AppendMenu(MF_SEPARATOR);
//创建层叠菜单时,AppendMenu的第2个参数是层叠菜单的句柄,第1个参数为MF_POPUP
mymenu.AppendMenu(MF_POPUP, (UINT)newmenu.m_hMenu, strWH ); mymenu.AppendMenu(MF_CHECKED, 0x0040,"第 3 条(&T)");
mymenu.SetMenuItemBitmaps(0x0040,MF_BYCOMMAND,&uncheck_map,&check_map);
mymenu.AppendMenu(MF_STRING, 0x0050,"第 4 条(&D)"); mymenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, pt_to_screen.x, pt_to_screen.y, this);
}

4.2 窗口菜单

最后介绍一下如何在对话框窗口创建菜单,如图4.5所示:

方法很简单,只需要在BOOL CFDlg::OnInitDialog()函数中添加如下代码:

CMenu mymenu;

mymenu.LoadMenu(IDR_MENU1);

SetMenu(&mymenu);

mymenu.DestroyMenu();

其中ID号IDR_MENU1是在资源中创建一个菜单资源如图4.6所示:

最后对每个菜单选项进行ID号编辑后,即可在OnCommand函数中进行消息响应操作。

MFC技术积累——基于MFC对话框类的那些事儿5的更多相关文章

  1. MFC技术积累——基于MFC对话框类的那些事儿

    1. 创建对话框类 (1)打开VC++6.0环境,点击:文件→新建: (2)在弹出的新建对话框中选择:工程→MFC AppWizard (exe)→输入工程名称(例如:功能调试)→工程保存路径名→确定 ...

  2. MFC技术积累——基于MFC对话框类的那些事儿2

    3. 绘图 3.1 对话框资源编辑 首先通过添加控件的方式来创建一个简单的绘图对话框如图所示,创建步骤为: 第一.在VC++6.0软件环境的灰色空白区域右击,选中Controls,然后会弹出一个控件对 ...

  3. MFC技术积累——基于MFC对话框类的那些事儿3

    3.3.2 创建图形画刷来实现位图加载 1.首先在Resource View中导入一幅位图,位图大小96×96像素: 2.其次在主对话框中添加一个静态文本资源,ID号是IDC_BITMAPAREA,添 ...

  4. MFC技术积累——基于MFC对话框类的那些事儿4

    3.3.4 借助兼容DC加载DIB位图 创建一个与设备环境相兼容的DC,通过将位图暂时导入至兼容DC,然后利用CDC::BitBlt 或者CDC::StretchBlt函数将位图绘制到设备环境中. 示 ...

  5. MFC技术内幕系列之(四)---MFC消息映射与消息传递内幕

    ////////////////////////////////////////////////////////////////////////////////////                 ...

  6. MFC编程入门之八(对话框:创建对话框类和添加控件变量)

    创建好对话框资源后要做的就是生成对话框类了.生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数. 例程Addition是基于对话框的程序,所以程序自动创建了对话框模板IDD_ADDIT ...

  7. mfc 在VC的两个对话框类中传递参数的三种方法

    弄了好久,今天终于把在VC中的对话框类之间传递参数的问题解决了,很开心,记录如下: 1. 我所建立的工程是一个基于MFC对话框的应用程序,一共有三个对话框,第一个对话框为主对话框,所对应的类为CTMD ...

  8. 【转】VS2010/MFC编程入门之八(对话框:创建对话框类和添加控件变量)

    原文网址:http://www.jizhuomi.com/software/153.html 前两讲中鸡啄米为大家讲解了如何创建对话框资源.创建好对话框资源后要做的就是生成对话框类了.鸡啄米再声明下, ...

  9. VS2010/MFC对话框三:创建对话框类和添加控件变量

    创建对话框类和添加控件变量 前两讲中讲解了如何创建对话框资源.创建好对话框资源后要做的就是生成对话框类了.生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数等. 例程Addition是 ...

随机推荐

  1. hadoop异常:Be Replicated to 0 nodes, instead of 1

    Hadoop 坑爹的Be Replicated to 0 nodes, instead of 1 异常 博客分类: Java 编程 HadoopITeyeJSP算法Apache  有段时间不写博客了, ...

  2. SPOJ:Ada and Orange Tree (LCA+Bitset)

    Ada the Ladybug lives near an orange tree. Instead of reading books, she investigates the oranges. T ...

  3. iOS中NSNotification、delegate、KVO三者之间的区别与联系?

    前面分别讲了delegate.notification和KVO的实现原理,以及实际使用步骤,我们心中不禁有个疑问,他们的功能比较类似,那么在实际的编程中,如何选择这些方式呢? 在网上看到一个博客上详细 ...

  4. 【USACO】 Balanced Lineup

    [题目链接] 点击打开链接 [算法] 这是一道经典的最值查询(RMQ)问题. 我们首先想到线段树.但有没有更快的方法呢?对于这类问题,我们可以用ST表(稀疏表)算法求解. 稀疏表算法.其实也是一种动态 ...

  5. bzoj3143游走——期望+高斯消元

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3143 只需算出每条边被经过的概率,将概率从小到大排序,从大到小编号,就可得到最小期望: 每条 ...

  6. 重新安装VMware10提示"The Msi '' Failed"问题解决方案

    想把虚拟机软件升级以下,没想到卸载的时候不干净,再安装的时候总提示让我先卸载旧版本但实际上旧版本已经卸载过了,这里又没法再卸载一次,所以就提示”The MSI '' failed“ 显然,安装程序还是 ...

  7. 交通规划_dijkstra

    问题描述 G国国王来中国参观后,被中国的高速铁路深深的震撼,决定为自己的国家也建设一个高速铁路系统. 建设高速铁路投入非常大,为了节约建设成本,G国国王决定不新建铁路,而是将已有的铁路改造成高速铁路. ...

  8. 深度解密Go语言之 map

    目录 什么是 map 为什么要用 map map 的底层如何实现 map 内存模型 创建 map 哈希函数 key 定位过程 map 的两种 get 操作 如何进行扩容 map 的遍历 map 的赋值 ...

  9. rbenv的使用

    创建: 2017/09/05 更新: 2018/02/03 增加更新rbenv和获取list没有的版本 更新: 2018/02/25 把path里面[个人主机名]全部替换为[主机名] 更新: 2018 ...

  10. Java 反射机制详解(下)

    续:Java 反射机制详解(上) 三.怎么使用反射 想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属 ...