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. kali-linux简单学习

    一. curl --head 返回操作系统的版本 同样的Xprobe2可以和nmap一起返回操作系统的版本 nmap 直接加域名或者ip地址,比较权威判断操作系统版本,或者服务版本,以及开的端口 nm ...

  2. JNI(Java Native Interface)

    一.JNI(Java Native Interface)        1.什么是JNI:               JNI(Java Native Interface):java本地开发接口   ...

  3. Oracle的db.properties文件

    转自:https://blog.csdn.net/lssqk/article/details/79133829

  4. csacademy Round #36(模拟+最坏情况)

    传送门 题意 给出n种袜子,每种袜子个数a[i],两只相同种类袜子配成一对,询问至少拿出多少只袜子能确保配出k对袜子 分析 In order to find out the minimum numbe ...

  5. 几题LCS后的小总结

    先得理解最长上升子序列吧,这还是非常简单的. 然后就是要真正理解LCS: 真正理解源于做题,做题就像查漏补缺一样,你总有不会的地方. 非常彻底地理解该图(还是去做题啦) = =瞎几把乱说有两种问题 [ ...

  6. hdoj1596【spfa,松弛】

    积压很久的一道...一看直接spfa水过..但是看那个safest怎么求得?松弛的时候取大. #include <bits/stdc++.h> using namespace std; t ...

  7. keepalived 原理、安装与使用

    1. keepalived工作原理 keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防止单点故障. keepalived是以VRRP协议为实现基础的, ...

  8. JAVA多线程(二) 并发队列和阻塞队列

    github代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-service/ ...

  9. .net mvc中一种简单的工作流的设计

    开篇前的废话:工作流是我们在做互联网应用开发时经常需要用到的一种技术,复杂的工作流我们基本是借助一些开源的 工作流项目来做,比如 ccflow等,但是有时候,我们只需要实现一些简单的工作流流程,这时候 ...

  10. The Django Book学习笔记 04 模板

    如果使用这种方法制作文章肯定不是一个好方法,尽管它便于你理解是怎么工作的. def current_datetime(request): now = datetime.datetime.now() h ...