首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
80 阅读
2
nvim番外之将配置的插件管理器更新为lazy
58 阅读
3
2018总结与2019规划
54 阅读
4
PDF标准详解(五)——图形状态
33 阅读
5
为 MariaDB 配置远程访问权限
30 阅读
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
Java
emacs
linux
文本编辑器
elisp
反汇编
OLEDB
数据库编程
数据结构
内核编程
Masimaro
累计撰写
308
篇文章
累计收到
27
条评论
首页
栏目
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
页面
归档
友情链接
关于
搜索到
2
篇与
的结果
2015-08-05
菜单的使用
# Windows菜单的基本知识:1)顶级菜单:紧贴在标题栏下面的菜单称为顶级菜单,也可以叫做程序的主菜单;2)弹出式菜单:一般在顶级菜单上都有很多菜单项,单击这些菜单项时会弹出一个下拉式的菜单项,我们点击的这个菜单称为弹出式菜单3)菜单项:每一个可选菜单项被赋予一个唯一的ID,当用户单击某个菜单项时Windows会将该菜单项的ID发送给父窗口,父窗口通过WM_COMMAND消息处理菜单的单击消息,但是弹出式菜单没有ID,WM_COMMAND消息也不处理弹出式菜单的点击信息4)菜单加速键:主要是多个键的组合,当同时按下这些键的时候相当于点击了菜单的某个菜单项5)菜单项一般具有“可用”(Enabled)、“不可用”(disabled)、“变灰”(gray)几种选项,其中变灰选项将菜单项变成不可用的同时也会将菜单项变成灰色,所以当我们需要禁用某个菜单项的时候最好将它变灰,以便提示用户;6)菜单句柄:每一种菜单都有一个菜单句柄,包括弹出式菜单的菜单项,顶级菜单,弹出式菜单;菜单的创建:Windows中菜单有两种方式,一种是通过资源的方式通过可视化或者编写rc文件来创建一个菜单资源,并在代码中显示的加载,另一种是通过调用CreateMenu、AppendMenu、InsertMenu等函数创建菜单并插入相应的菜单项,下面对这两种方式一一进行说明:1)采用rc文件的方式:可以在visual studio中利用可视化的方式编辑菜单,在这里就不在说明,而需要手工编写rc文件请参考我的另外一篇博文当我们编辑好了rc文件之后有三种方法添加菜单:通过在创建窗口类的时候在lpszMenuName项的后面添加一个用于标示菜单的字符串,若菜单使用的是ID号作为标示那么可以使用宏MAKEINTRESOURCE;在函数CreateWindow或者CreateWindowEx中的相应参数中填入菜单句柄,为了获取这个句柄需要提前使用LoadMenu函数加载菜单,这个函数的功能是将资源文件中的菜单加载到内存,并返回一个菜单句柄,函数的原型如下:HMENU LoadMenu( HINSTANCE hInstance, // 当前应用程序的实例句柄 LPCTSTR lpMenuName // 菜单唯一标示,可以是字符串或者用MAKEINTRESOURCE转化而来的字符串 );第三种方式是先通过LoadMenu函数获取菜单句柄后在窗口创建后通过SetMenu函数设置菜单,该函数用于为指定窗口加载一个顶级菜单、该函数原型如下:BOOL SetMenu( HWND hWnd, // 需加载菜单的窗口句柄 HMENU hMenu // 菜单句柄 );各个方式的源代码如下:WNDCLASS wd = {0}; wd.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wd.hCursor = LoadCursor(NULL, IDC_ARROW); wd.hIcon = LoadIcon(NULL, IDI_APPLICATION); wd.hInstance = hInstance; wd.lpfnWndProc = WindowProc; wd.lpszClassName = "MenuClass"; //第一种方式 //wd.lpszMenuName = MAKEINTRESOURCE(IDM_MENU); wd.style = CS_HREDRAW | CS_VREDRAW; HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDM_MENU)); //加载加速键 HACCEL hAccelerator = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDA_MAIN)); if (!RegisterClass(&wd)) { int nErr = GetLastError(); return nErr; } //第二种方式 //HWND hWnd = CreateWindow("MenuClass", "Menu", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, hMenu, hInstance, NULL); //第三种方式 HWND hWnd = CreateWindow("MenuClass", "Menu", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); SetMenu(hWnd, hMenu);如果采用函数动态创建的方式,需要如下几个步骤:1)通过函数CreateMenu()创建一个顶级菜单;2)通过CreateMenu()创建一个弹出式菜单;3)利用AppendMenu()或者InsertMenu()向弹出式菜单中插入菜单项;4)利用AppendMenu()将弹出式菜单插入到顶级菜单中;5)用SetMenu函数将创建好的菜单加到程序下面分别说明这些函数的功能和用法:CreateMenu()用于创建一个菜单(函数会将菜单初始化为空菜单),并返回一个菜单句柄,函数原型如下:HMENU CreateMenu(VOID) AppendMenu()用于在顶级菜单、弹出式菜单的最后面的菜单项后查入新菜单项,函数原型如下: BOOL AppendMenu( HMENU hMenu, // 菜单项的句柄 UINT uFlags, // 新菜单项的类型,主要使用的是MF_STRING、MF_POUP(弹出式菜单) UINT uIDNewItem, // 新菜单项的ID,如果是弹出式菜单、则使用菜单的句柄 LPCTSTR lpNewItem //该值取决于第二个参数,若为MF_STRING则应该是一个以0结尾的字符串 ); InsterMenu()函数作用与AppendMenu相同,函数原型如下: BOOL InsertMenu( HMENU hMenu, // 菜单项的句柄 UINT uPosition, // 新菜单项的识别方式,主要有两种MF_BYCOMMAND和MF_BYPOSITION,在以后我们取菜单项的句柄或者对菜单项做其他操作,需要辨认时会有一定的作用,主要表明是靠ID号辨别还是靠在菜单中的相对位置(以0为第一个菜单项) UINT uFlags, // 新菜单项的类型,主要使用的是MF_STRING、MF_POUP(弹出式菜单) UINT uIDNewItem, // 新菜单项的ID,如果是弹出式菜单、则使用菜单的句柄 LPCTSTR lpNewItem //该值取决于第三个个参数,若为MF_STRING则应该是一个以0结尾的字符串 );下面是一个使用这种方式的例子#include <Windows.h> LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #define IDM_FILE 100 #define IDM_ABOUT 200 #define IDM_CLOSE 300 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { WNDCLASS wd = {0}; wd.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wd.hCursor = LoadCursor(NULL, IDC_ARROW); wd.hIcon = LoadIcon(NULL, IDI_APPLICATION); wd.hInstance = hInstance; wd.lpfnWndProc = WindowProc; wd.lpszClassName = "MenuClass"; wd.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClass(&wd)) { int nErr = GetLastError(); return nErr; } HWND hWnd = CreateWindow("MenuClass", "Menu", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); //创建主菜单 HMENU hMenu = CreateMenu(); //创建弹出式菜单 HMENU hPopup = CreateMenu(); //向弹出式菜单中插入菜单项 AppendMenu(hPopup, MF_STRING, IDM_FILE, TEXT("文件")); AppendMenu(hPopup, MF_STRING, IDM_ABOUT, TEXT("关于")); InsertMenu(hPopup, MF_BYCOMMAND, MF_STRING, IDM_CLOSE, TEXT("关闭")); //将弹出式菜单插入到主菜单中 AppendMenu(hMenu, MF_POPUP,(UINT_PTR)hPopup, TEXT("系统")); SetMenu(hWnd,hMenu); if (NULL == hWnd) { int nErr = GetLastError(); return nErr; } ShowWindow(hWnd, nShowCmd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: { if (IDM_ABOUT == LOWORD(wParam)) { MessageBox(hWnd, TEXT("About"), TEXT("TEST"), MB_OK); } } break; case WM_CLOSE: DestroyWindow(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; }键菜单的使用:创建一个右键菜单有如下步骤(在WM_RBUTTONDOWN消息下处理):1)创建一个可用的菜单(一般是主菜单);2)根据主菜单获取弹出式菜单的句柄,使用函数GetSubMenu()2)加载菜单项3)获取鼠标点击的位置4)将客户区坐标转化为屏幕坐标(这一步千万别忘了)5)调用TrackPopupMenu函数,该函数用来显示一个快捷菜单,这个函数中需要填入菜单显示的位置,这个位置值为屏幕坐标,这也就是我们为什么需要转化坐标的原因;该函数的原型为:BOOL TrackPopupMenu( HMENU hMenu, // 快捷菜单的句柄 UINT uFlags, // 快捷菜单显示的类型 int x, // int y, //菜单显示点的坐标,根据第二个参数确定如何显示,一般有左对齐(最左边顶点为该坐标)、右对齐(右上角坐标为该坐标)、中间对齐(上边线的中点坐标为该坐标); int nReserved, // 该参数必须给0 HWND hWnd, // 显示快捷菜单的窗口句柄 CONST RECT *prcRect // 该参数被忽略,一般给NNULL );下面是一段例子代码:HMENU hMenu = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDM_MENU)); hMenu = GetSubMenu(hMenu, 0); POINT ptChick = {LOWORD(lParam), HIWORD(lParam)}; ClientToScreen(hWnd, &ptChick); TrackPopupMenu(hMenu, TPM_LEFTALIGN, ptChick.x, ptChick.y, 0, hWnd, NULL);其他菜单操作的函数主要有:GetSystemMenu()获取系统菜单句柄;Deletemenu()从菜单中删除某一菜单项并销毁它RemoveMenu()从菜单中移出某一菜单项但不销毁它InsertMenu()在菜单中插入一个菜单项NodifyMenu()修改一个已存在的菜单项
2015年08月05日
6 阅读
0 评论
0 点赞
2015-07-15
Windows程序设计学习笔记(五)——菜单资源和加速键的使用
菜单可能是Windows提供的统一用户界面中最重要的一种方式,菜单通常在标题栏的下一行显示,这一栏叫做菜单栏,菜单栏中的每一项称之为菜单项,菜单栏中的每一个菜单项在激活时会显现一个下拉菜单(也可以说是它的子菜单),下拉菜单中也可以有多个菜单项,每个菜单项又可以有子菜单,每个菜单项都有一个唯一的数字标示,称为菜单项的ID,但是有子菜单的菜单项没有ID。用户点击某项后,会产生一个WM_COMMAND消息发送到其父窗口,该消息中包含了这个菜单项的ID。菜单的创建可以通过可视化的方法创建,也可以通过编写资源脚本的方式创建菜单资源,在这里重点说明如何通过脚本编写的方式创建菜单//Menu IDM_MENU MENU BEGIN POPUP "文件(&F)" BEGIN MENUITEM "打开(&O)", IDM_OPEN MENUITEM "关闭(&C)", IDM_OPTION MENUITEM SEPARATOR MENUITEM "关闭(&X)", IDM_EXIT END POPUP "查看(&V)" BEGIN MENUITEM "字体(&V)...\tAlt + F", IDM_SETFONT MENUITEM "背景色(&B)...\tCtrl + Alt + B", 40009 MENUITEM SEPARATOR MENUITEM "被禁用的菜单项", ID_40010, INACTIVE MENUITEM "变绘的菜单项", ID_40011, GRAYED MENUITEM "大图标(&G)", 40012 MENUITEM "小图标(&M)", IDM_SMALL MENUITEM "列表(&L)", 40015 MENUITEM SEPARATOR MENUITEM "详细信息(&D)", IDM_DETAIL POPUP "工具栏" BEGIN MENUITEM "标准按钮(&S)", 40019 MENUITEM "文字标签(&C)", 40020 MENUITEM "命令栏(&I)", 40021 END MENUITEM "状态栏(&U)", 40022 END POPUP "帮助(&H)", HELP BEGIN MENUITEM "帮助主题(&H)\tF1", IDM_HELP MENUITEM "关于本程序(&A)...", 40025 END END IDA_MAIN ACCELERATORS BEGIN VK_F1, IDM_HELP, VIRTKEY, NOINVERT "B", IDM_SETCOLOR, VIRTKEY, CONTROL, ALT, NOINVERT "F", IDM_SETFONT, VIRTKEY, ALT, NOINVERT END下面来分析这段代码:首先是通过一些列的宏定义来定义各种菜单项的ID,菜单ID用于唯一标识一个菜单项,不同的菜单项所用的ID号应该不同除非这些菜单项完成相同的工作,菜单项的ID可以是16位的整数,同时菜单项也可以用字符串来表示,在调用相应的API函数的时候检测到这个值大于10000h的时候将它作为字符串指针,这个时候用字符串唯一标示菜单项,当这个数小于10000h时表示的是一个数字,这个时候用数字唯一标示。菜单在脚本中的定义格式为:菜单ID MENU [DISCARDABLE] BEGIN 菜单项的定义 END菜单ID:每个菜单都有的一个唯一的标示,可以是字符串,可以是数字。DISCARDABLE:菜单的内存属性,标示菜单在不再使用的时候可以暂时从内存中释放以节省内存菜单项的定义方法有3种分别对应不同类型的菜单项:MENUITEM 菜单文字,命令ID, [选项列表](用法1) MENUITEM SEPARATOR (用法2) popup 菜单文字 [,选项] BEGIN MENUITEM 菜单文字,命令ID, [选项列表] ......................... END (用法3)用法1:用于创建一个菜单项;用法2:用于创建一个分割符;用法3:用于创建一个菜单项的子菜单项;菜单文字:显示在菜单项上的文字,需要字符串中某个字母带下划线的话,可以在字母前面加上一个&符号,比如上面的“状态栏(&U)”,带下划线的字母被系统当做快捷键,比如我们点击查看菜单项,打开它的子菜单,在按下字母U就相当于直接点击菜单中的状态栏一项;命令ID:上述我们定义的菜单ID项,父窗口的WM_COMMAND消息的参数中带有这个值,通过这个值判断是哪个菜单项被点击;选项列表:用来定义菜单项的各种属性,他可以是下面的值:CHECKED——表示打上选定标志(菜单项前有一个钩)GRAYED——菜单项变灰INAVTIVE——菜单项不可用MENUBREAK或者MENUBARBREAK——表示这个菜单项和以后的菜单项在新的一列显示;对于popup后面的选项可以是下面值的一个:GRAYED——菜单项变灰INAVTIVE——菜单项不可用HELP——菜单项靠右边显示快捷键的定义格式为:快捷键ID ACCELERATORSBEGIN 键名, 命令 [, 类型] [,选项] END键名:表示加速键对应的按键,可以有3中方式定义:“^字母” :表示Ctrl加上字母”字母“:表示字母,这时类型必须指明为VIRTKEY数值:表示ASCii码为该数值的字母,这个时候类型必须指明为ASCii命令ID:按下加速键以后Windows向程序发送的命令ID,如果想把加速键和菜单项关联起来,这里就是相应的菜单项的ID类型:用以指定键的定义方式,可以是ASCii或者VIRTKEY选项:可以是Alt、control、shift中的一个或多个,表示这些键和键名定义的键一起组成一个快捷键菜单项的消息响应:菜单项的处理一般由菜单父窗口处理,菜单被选中中时会向其父窗口发送一条WM_COMMAND的消息,将该项的相关信息告诉给其父窗口,该消息的说明如下:WM_COMMAND wNotifyCode = HIWORD(wParam); // 通知码 若对应的资源为加速键该值为1,若为菜单项则为0 wID = LOWORD(wParam); // 菜单项、加速键、控件的ID hwndCtl = (HWND) lParam; // 控件句柄我们可以在WM_COMMAND消息的处理中添加如下的内容,让其显示我们选中的是那一项:if (IDM_HELP == LOWORD(wParam)) { MessageBox(hWnd, "您选中了帮助主题菜单项","提示", MB_OK); }当选择“帮助主题”的时候,会弹出一个消息框,如果按下F1键也会显示这样一个消息框,因为我们已经将加速键绑定到对应的菜单项上面。
2015年07月15日
6 阅读
0 评论
0 点赞