WIN 下的超动态菜单(二)用法
WIN 下的超动态菜单(二)用法
作者:黄山松,发表于博客园:http://www.cnblogs.com/tomview/
auto_dynamenu 是一个动态生成WINDOWS菜单的c++封装库,设计思路是要尽量简化动态菜单的生成代码,在程序界面任何地方想要显示菜单(特别是右键菜单)的时候,可以方便生成菜单,特别可以根据程序当时的内部数据,内部状态来生成不同的动态菜单。
auto_dynamenu 只封装了一个静态的接口函数,这样处理的目的是把类的实现代码可以放在头文件的类的声明里面,这样使用的时候只要包含头文件就可以直接调用了,不需要把实现文件加入工程,简化操作。
类的接口函数定义
/**************************************************************************************************\
* static int : 返回值,表明选择了哪个菜单项或者被更新的 nDefaultValue
* dynamenu :
* HWND hWnd : 当前窗口句柄
* LPPOINT pPoint : 显示菜单的位置,通常为0即可,自动确定显示的菜单位置
* char* pszMenu : 表明动态菜单内容的菜单字符串
* int nDefaultMode : 自动更新菜单选择标记的模式,0 无,1 等于模式,2 位模式
* int nDefaultValue : 缺省值,根据这个值,按照 nDefaultMode 来显示菜单项的选择标记
\**************************************************************************************************/
class auto_dynamenu
{
public:
static int dynamenu(HWND hWnd, LPPOINT pPoint, char* pszMenu, int nDefaultMode, int nDefaultValue);
};
参数:pszMenu
接口用一个格式化的字符串 pszMenu 来表示动态菜单,具体格式规则如下:
(1)每个菜单项为一个以 \n 结束的字符串
(2)菜单项的字符串通常以等号 = 分割为两部分,等号前面为要显示的菜单内容,等号后面为选择这个菜单后的取值
(3)菜单项的字符串里面如果没有等号,表明选择菜单返回的时候,返回的是菜单项字符串
(3)每个菜单项字符串前面可以加如下的修饰符:
[a] *(星号):表示这个菜单项前面有点的选择标记
[b] ^:表示这个菜单项前面有对勾的选择标记
[c] #:表示这个菜单项是灰色的
[d] -(减号):表明这个菜单项和下一个菜单项之间分为不同的列(多列的菜单)
[e] `(键盘左上角的按键):表示一个没有意义的占位符
[f] ~:表明是一个菜单分割线
(4)可以用单独一行的 ~ 表示一个菜单分割横线,“~\n”
(5)菜单项字符串等号前面部分的竖线字符”|“ 把菜单分割为父菜单和子菜单
(6)把不同的菜单项的字符串连接为一个完整的字符串就可以描述这个整个菜单了
例如:
char szMenu[] =
"选项1=20\n" //选项1对应数值20,选择这个函数返回20
"选项2=0x20\n" //选择2对应数值0x20,选择这个函数返回0x20
"选项3=0\n" //选项3对应数值0,选择这个函数返回 INT_MAX(因为函数返回0代表没有选择菜单项,所以0用INT_MAX返回值表示)
"~\n" //这个代表一个菜单分割横线
"录像|通用格式|avi格式=-1\n" //多级子菜单,选择这个返回-1
"录像|通用格式|~\n" //多级子菜单内部的分割横线
"录像|通用格式|mkv格式=-2\n" //多级子菜单,选择这个返回-2
"录像|~\n"
"录像|专用格式|rdv格式=-3\n" //多级子菜单,选择这个返回-3
"~\n"
"#暂停处理\n" //灰色禁用的菜单项,无法选择,可以用于显示信息
"~\n"
"控制|^开始视频=10\n" //显示选中的视频开始菜单,选择返回10
"控制|结束视频=11\n" //显示没有选中的菜单,选择返回11
"播放当前录像 1.avi=d:\\1.avi\n" //返回文件名字符串指针
;
上面的示例菜单字符串显示出来的菜单如下:

参数:hWnd
虽然菜单的消息不发往任何窗口,但是这个必须指定一个有效的窗口句柄,否则菜单显示不出来。通常指定对鼠标右键响应要显示菜单的窗口,或者主窗口。
参数:pPoint
菜单显示位置坐标POINT的指针,用于指定菜单的显示位置,是屏幕坐标。通常可以给0,这时程序自动选择菜单的显示位置,通常根据鼠标当前位置的控件类型确定,具体如下:
(1)如果是 BUTTON,工具栏上的按钮,则显示在这个控件的下方,左侧对齐
(2)如果是TreeView,ListView则显示在当前鼠标位置的条目的下方
(3)如果是TabCtrl则显示在鼠标当前的Tab页的页头的下方
(4)大小像个按钮的ActiveX控件,显示在下方
(5)其他显示在鼠标的当前位置
参数pPoint备注:
在这个参数给0的时候,代码自动确定菜单显示位置,但由于作者通常在VC6下编程(参见博文《我是如何把VC6一直用到2016年的》),因此代码中判断控件类型用的 ClassName 没有包含新版 Visual C 带的控件的类,可能需要使用者增加一些代码中的控件类名,对不同的控件确定不同的显示菜单的位置。具体情况参考文档《WIN 下超动态菜单(三)代码》。
参数:nDefaultMode
缺省模式,如果为0,没有缺省模式,菜单项的标记都在菜单字符串中指定。
如果为1,相等模式,如果某个菜单项的取值等于传入的nDefaultValue则显示选中标记。
如果为2,为与模式,如果某个菜单项的取值与nDefaultValue的位与不为0,则显示选中标记。
参数:nDefaultValue
当前的缺省值,配合nDefaultValue使用。
返回值:
程序应该根据返回值来判断选择了哪个菜单,根据nDefaultMode不同含义有差别,用法也有差异。
(1)如果nDefaultMode为0
(a)返回值为0的时候,表明没有选择任何菜单选项;
(b)返回值为INT_MAX,表明选择了某个值为0的菜单项;
(c)如果选择的菜单项字符串里面有等号,并且等号后面是数字(支持十进制和十六进制写法),则返回这个数字;
(d)如果选择的菜单项字符串里面的等号后面是字符串,则返回这个等号后面的字符串的指针;
(e)如果选择的菜单项字符串里面没有等号,则返回这个菜单项的字符串的指针。
(2)如果 nDefaultMode 为 1 或者 2
则返回nDefaultValue经过修改后的值,如果没有选择任何菜单,返回值等于nDefaultValue。
直接可以这样写 :
nDefaultValue = auto_dynamenu::dynamenu(GetSafeHwnd(), 0, pszMenu, nDefaultMode/*1 or 2*/, nDefaultValue);
动态菜单显示及根据返回值进行处理示例
char szMenu[] =
"选项1=20\n" //选项1对应数值20,选择这个函数返回20
"选项2=0x20\n" //选择2对应数值0x20,选择这个函数返回20
"选项3=0\n" //选项3对应数值0,选择这个函数范围 INT_MAX(因为函数返回0代表没有选择菜单项,所以0用INT_MAX返回值表示)
"~\n" //这个代表一个菜单分割横线
"录像|通用格式|avi格式=-1\n" //多级子菜单,选择这个返回-1,可以为负值
"录像|通用格式|~\n" //多级子菜单内部的分割横线
"录像|通用格式|mkv格式=-2\n" //多级子菜单,选择这个返回-2
"录像|~\n"
"录像|专用格式|rdv格式=-3\n" //多级子菜单,选择这个返回-3
"~\n"
"#暂停处理\n" //灰色禁用的菜单项,无法选择,可以用于显示信息
"~\n"
"控制|^开始视频=10\n" //显示选中的视频开始菜单,选择返回10
"控制|结束视频=11\n" //显示没有选中的菜单,选择返回11
"播放当前录像 1.avi=d:\\1.avi\n" //返回文件名字符串指针
; int index = auto_dynamenu::dynamenu(GetSafeHwnd(), 0, szMenu, 0, 0);
switch (index)
{
case 0:
//菜单没有选择,不做任何处理
break;
case 20:
//选项1
break;
case 0x20:
//选项2
break;
case INT_MAX:
//选项3,这个菜单项的值为0,通常可以避免这样的情况,就不需要处理这个特殊的值了
break;
case -1:
//avi 录像
break;
case -2:
//mkv录像
break;
case -3:
//rdv录像
break;
case 10:
//开始视频
break;
case 11:
//停止视频
break;
default:
{
char * pfile = (char*)index;
//选中了最后的文件菜单项,pfile为 “d:\\1.avi” 字符串的指针
}
break;
}
两点注释:
(1)上面的代码里面的菜单项的选中标记,都是在菜单字符串里面手工指定的,这时 nDefaultMode 和 nDefaultValue 指定为0。
(2)上面代码中的菜单项是在源代码中硬编码的,实际使用的时候可以动态生成,根据程序的状态来组建菜单字符串,例如:
char szMenu[1024] = {0};
int n = 0;
if (value == 2)
n += sprintf(szMenu + n, "^");
n += sprintf(szMenu + n, "值2=2\n");
if (value == 4)
n += sprintf(szMenu + n, "^");
n += sprintf(szMenu + n, "值4=4\n");
nDefaultMode=1时的示例
(1)模式1为相等模式 ( nDefaultMode = 1 ),当某个菜单项的数值等于输入的 nDefaultValue 的时候,这个菜单项前面有选中标记

int val = 32; //nDefaultValue
char szMenu[] =
"整数1=1\n"
"整数20=20\n"
"整数32=32\n"
"整数0x99=0x99\n"
;
//注意上面的菜单字符串里面没有选中标记
//nDeaultMode = 1,当菜单项等于 nDefaultValue的时候显示选中标记
val = auto_dynamenu::dynamenu(GetSafeHwnd(), 0, szMenu, 1, val);
//返回值为当前选中的菜单项对应的值,如果没有选择菜单,这个值保持原来的不变
nDefaultMode=2时的示例
模式2为位模式 ( nDefaultMode = 2 ),当菜单项的数值所对应的位 与nDefaultValue位与的时候不为0,则菜单项前面显示选中标记。

DWORD flags = 0x82; //当前的值 nDefaultValue
char szMenu[] =
"标记1=1\n"
"标记2=2\n"
"标记3=4\n"
"标记4=8\n"
"标记5=0x10\n"
"标记6=0x20\n"
"标记7=0x40\n"
"标记8=0x80\n"
;
//上面的菜单字符串内没有选择标记,程序自动根据 nDefaultValue 把对应的位加上选中标记
//nDefaultMode = 2
flags = (DWORD)auto_dynamenu::dynamenu(GetSafeHwnd(), 0, szMenu, 2, flags);
//返回值就是flags,如果没有选择菜单项,那么这个值不变
下载
可以在下面的链接下载代码和示例程序:
http://files.cnblogs.com/files/tomview/dynamenu_20160524.rar
WIN 下的超动态菜单(二)用法的更多相关文章
- WIN 下的超动态菜单(三)代码
WIN 下的超动态菜单(一)简介 WIN 下的超动态菜单(二)用法 WIN 下的超动态菜单(三)代码 作者:黄山松,发表于博客园:http://www.cnblogs.com/tomview/ 超动态 ...
- WIN 下的超动态菜单(一)
WIN 下的超动态菜单(一)介绍 WIN 下的超动态菜单(二)用法 WIN 下的超动态菜单(三)代码 作者:黄山松,发表于博客园:http://www.cnblogs.com/tomview/ ...
- Bootstrap历练实例:导航内下拉菜单的用法
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- .net core3.1 abp动态菜单和动态权限(思路) (二)
ps:本文需要先把abp的源码下载一份来下,跟着一起找实现,更容易懂 在abp中,对于权限和菜单使用静态来管理,菜单的加载是在登陆页面的地方(具体是怎么知道的,浏览器按F12,然后去sources中去 ...
- Win下最爱效率利器:AutoHotKey
AutoHotkey是一个windows下的开源.免费.自动化软件工具.它由最初旨在提供键盘快捷键的脚本语言驱动(称为:热键),随着时间的推移演变成一个完整的脚本语言.但你不需要把它想得太深,你只需要 ...
- 动态创建二维vector数组 C和C++ 及指针与引用的区别
二维vectorvector<vector <int> > ivec(m ,vector<int>(n)); //m*n的二维vector 动态创建m*n的二 ...
- 【vue】iView-admin2.0动态菜单路由
vue项目实现动态路由有俩种方式 一.前端在routers中写好--所有--路由表 <前端控制路由>,登录时根据用户的角色权限来动态的显示菜单路由 二.前端通过调用接口请求拿到当前用户-- ...
- 转帖: 一份超全超详细的 ADB 用法大全
增加一句 连接 网易mumu模拟器的方法 adb connect 127.0.0.1:7555 一份超全超详细的 ADB 用法大全 2016年08月28日 10:49:41 阅读数:35890 原文 ...
- Delphi编程中动态菜单要点归纳
一.创建菜单并添加项目 在设计程序时,有时需要动态创建菜单, 通常使用以下的语句: PopupMenu1 := TPopupMenu.Create(Self); Item := TMenuIte ...
随机推荐
- codeforces 700A As Fast As Possible 二分求和?我觉得直接解更好
分析:一辆车最多载k个人,车的速度肯定比人快,所以想要到达时间最短,那么每个人必须做一次公交车.那么把n个人分成p=(n+k-1)/k组.设最短时间为t,每人乘车时间为t1,则t1*v2+(t-t1) ...
- ahjesus 单词单数-复数相互转换C#
看codesmith内置的模板在生成存储过程的时候有单复数的转换,用相同的函数名实现了一个 public static class StringUtil { /// <summary> / ...
- Hadoop学习笔记1-如何简单布署hadoop
企业机型配置: 选型标准:普通的,廉价的,标准的(容易替换的),工业化大规模生产的 CPU:支持多核CPU,如2个4核CPU 内存:16G以上,内存越大,常用数据都缓存在内存,提高速度 硬盘:不需RA ...
- ImFire即时通讯系统构建(架构)
msgServer集群(ms) 设计作用: 该服务主要提供客户端的接入服务.每个ms维护当前接入用户的用户状态和心跳,每个ms地位是对等的. 设计考虑: ms之间不会直接交互,减少交互的复杂度.在用户 ...
- javascript 异步模块加载 简易实现
在javascript是没有类似java或其他语言的模块概念的,因此也不可能通过import或using等关键字来引用模块,这样造成了复杂项目中前端代码混乱,变量互相影响等. 因此在复杂项目中引入AM ...
- BitcoinJS - 支持比特币交易的 JavaScript 库
BitcoinJS 是一个干净,可读的 JavaScript 开发库,用于比特币交易.支持 Node.js 平台和浏览器端.已有超过150万的钱包用户在使用, BitcoinJS 是几乎所有的 Web ...
- Repeater分页代码
//ASP.NET中的DataList和Repeater提供了简单快速的方法來显示,其间,我们可以使用<ItemTemplate>更是使我们能随心所欲的控制数据的排放样式! //.可惜的是 ...
- JavaScript学习笔记-实例详解-类(二)
实例详解-类(二) //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...
- 在 Xamarin.Android 中使用 Notification.Builder 构建通知
0 背景 在 Android 4.0 以后,系统支持一种更先进的 Notification.Builder 类来发送通知.但 Xamarin 文档含糊其辞,多方搜索无果,遂决定自己摸索. 之前的代码: ...
- 更改SharePoint 2007/2010/2013 Web 应用程序端口号
之前创建的Web应用程序端口为80,因为其他需要要将端口更改为85,下面是具体步骤: 第一步:更改IIS绑定. 打开IIS服务管理器,右击需要更改的站点,选择编辑绑定. 在打开的网站绑定窗口,选择端口 ...