MFC技术积累——基于MFC对话框类的那些事儿5
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的更多相关文章
- MFC技术积累——基于MFC对话框类的那些事儿
1. 创建对话框类 (1)打开VC++6.0环境,点击:文件→新建: (2)在弹出的新建对话框中选择:工程→MFC AppWizard (exe)→输入工程名称(例如:功能调试)→工程保存路径名→确定 ...
- MFC技术积累——基于MFC对话框类的那些事儿2
3. 绘图 3.1 对话框资源编辑 首先通过添加控件的方式来创建一个简单的绘图对话框如图所示,创建步骤为: 第一.在VC++6.0软件环境的灰色空白区域右击,选中Controls,然后会弹出一个控件对 ...
- MFC技术积累——基于MFC对话框类的那些事儿3
3.3.2 创建图形画刷来实现位图加载 1.首先在Resource View中导入一幅位图,位图大小96×96像素: 2.其次在主对话框中添加一个静态文本资源,ID号是IDC_BITMAPAREA,添 ...
- MFC技术积累——基于MFC对话框类的那些事儿4
3.3.4 借助兼容DC加载DIB位图 创建一个与设备环境相兼容的DC,通过将位图暂时导入至兼容DC,然后利用CDC::BitBlt 或者CDC::StretchBlt函数将位图绘制到设备环境中. 示 ...
- MFC技术内幕系列之(四)---MFC消息映射与消息传递内幕
//////////////////////////////////////////////////////////////////////////////////// ...
- MFC编程入门之八(对话框:创建对话框类和添加控件变量)
创建好对话框资源后要做的就是生成对话框类了.生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数. 例程Addition是基于对话框的程序,所以程序自动创建了对话框模板IDD_ADDIT ...
- mfc 在VC的两个对话框类中传递参数的三种方法
弄了好久,今天终于把在VC中的对话框类之间传递参数的问题解决了,很开心,记录如下: 1. 我所建立的工程是一个基于MFC对话框的应用程序,一共有三个对话框,第一个对话框为主对话框,所对应的类为CTMD ...
- 【转】VS2010/MFC编程入门之八(对话框:创建对话框类和添加控件变量)
原文网址:http://www.jizhuomi.com/software/153.html 前两讲中鸡啄米为大家讲解了如何创建对话框资源.创建好对话框资源后要做的就是生成对话框类了.鸡啄米再声明下, ...
- VS2010/MFC对话框三:创建对话框类和添加控件变量
创建对话框类和添加控件变量 前两讲中讲解了如何创建对话框资源.创建好对话框资源后要做的就是生成对话框类了.生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数等. 例程Addition是 ...
随机推荐
- CodeForces937B:Vile Grasshoppers(素数性质)
The weather is fine today and hence it's high time to climb the nearby pine and enjoy the landscape. ...
- iOS多线程 NSThread/GCD/NSOperationQueue
无论是GCD,NSOperationQueue或是NSThread, 都没有线程安全 在需要同步的时候需要使用NSLock或者它的子类进行加锁同步 "] UTF8String], DISPA ...
- border-collapse
表格边框,对于别的元素加上的边框不起作用 border-collapse : separate(默认) | collapse | inherit separate : 边框独立 效果图: collap ...
- python-day9-进程、线程、协程篇
python threading模块 线程有两种调用方式: 直接调用 import threading import time def sayhi(num): #定义每个线程要运行的函数 print( ...
- kubernetes1.13.1部署ingress-nginx-十一
一.Ingress 简介 (1) 在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的. 为了使外部的应用能够访问集群内的服务, 在Kubernetes ...
- 021--python装饰器
一.装饰器含义 装饰器本质就是函数,为其它函数添加附加功能 二.装饰器原则 1.不修改被修饰函数的代码 2.不修改被修饰函数的调用方式 三.装饰器知识 装饰器 = 高阶函数 + 函数嵌套 + 闭包 四 ...
- ubuntu设置里面怎么少了好多设置了比如桌面背景
哈哈 我也是醉了 这个虚拟机真的不好对付 解决办法:sudo apt-get install unity-control-center ok!
- (水题)洛谷 - P1603 - 斯诺登的密码
https://www.luogu.org/problemnew/show/P1603 有毒,大小写不检测,句号也不管. #include<bits/stdc++.h> using nam ...
- gcc降版本方法 - [学习]
[转载]转载时请以超链接形式标明文章原始出处和作者信息及本声明http://www.blogbus.com/huangw10-logs/182474992.html 周末折腾了一下午加一夜,终于弄明白 ...
- 使用c++的一些建议
1: 不要使用宏,用const或enum定义常量 用inline避免函数的额外调用(使用inline的函数,块里面尽量不要使用循环和递归) 用template去荷花一些函数或者类型 用namespac ...