本文章参考<Windows游戏编程大师技巧(第二版)>
在Windows Application 中创建菜单过程如下所示:
1. 创建菜单资源
2. 应用程序装载菜单资源
3. 应用程序响应菜单事件消息
1. 创建菜单资源
在创建菜单资源的时候, 可以使用两种方式: 一是使用IDE编辑器来创建菜单; 二是使用人工的方式编辑.rc文件. 第一种方式在很多MFC教材中都有使用. 我在这里主要介绍人工方式来编辑菜单资源, 有助于大家了解使用IDE编程的资源.
如果你在*.rc资源脚本中创建一个菜单资源, 都必须创建一个*.H文件与之相对应, 用于解决资源的标示符的符号引用问题. 但有一种意外, 菜单名必须是符号,不能使名称字符串. 下面是在*.rc文件中常见的MEMU描述的基本语法:
MENU_NAME MENU DISCARDABLE
{
POPUP “name”
{
MENUITEM “name”, MENU_ID
}
}
MENU_NAME可以是一个名称字符串或是一个符号, 关键字DISCARDABLE有点过时了但还是必须的. 菜单中的一级菜单定义都是以关键字POPUP开头的. 而菜单项是以MENUITEM定义的, 至于MENU_ID是在*.h文件中定义的. 如下例子:
// .RC资源文件中
MainMenu MENU DISCARDABLE
{
POPUP "File"
{
MENUITEM"Open", MENU_FILE_ID_OPEN
MENUITEM"Close", MENU_FILE_ID_CLOSE
MENUITEM"Save", MENU_FILE_ID_SAVE
MENUITEM"Exit", MENU_FILE_ID_EXIT
} // end popup
POPUP "Help"
{
MENUITEM"About", MENU_HELP_ABOUT
} // end popup
} // end top level menu
// .H文件中
// defines for the top level menu FILE
#define MENU_FILE_ID_OPEN 1000
#define MENU_FILE_ID_CLOSE 1001
#define MENU_FILE_ID_SAVE 1002
#define MENU_FILE_ID_EXIT 1003
// defines for the top level menu HELP
#define MENU_HELP_ABOUT 2000
在这里没有定义”MainMenu”, 这样可以通过字符串而不是ID来访问该菜单. 如果我向如下方式定义了该项的ID
#define MainMenu 100
必须使用MAKEINTRESOURCE(MainMenu)或MAKEINTRESOURCE(100)来访问该菜单资源.
如果想设置热键或者快捷键的话, 可以使用连字号(&)来达到这个功能. 例如:
MENUITEM “E&xit”, MENU_FILE_ID_EXIT
使x成为热键, 而
POPUP “&File”
使F成为通过Alt+F使用的快捷键
2. 装载菜单
在windows类的定义中, 定义菜单的代码是:
WNDCLASSEX wnd;
wnd.lpszMenuName = NULL; //默认情况下
只需要将它赋值为该菜单的名称:
wnd.lpszMenuName = “MainMenu”;
或
wnd.lpszMenuName = MAKEINTRESOURCE(MainMenu);
这样做的话, 创建的每个窗口都会有一个相同的菜单. 要解决该问题的话,可以在创建菜单过程中通过传递菜单句柄来将一个菜单指定给一个窗口. 通过LoadMenu()装载菜单资源, 如果成功的话会返回一个HMENU句柄.
LoadMenu()原型:
HMENU LoadMenu(HINSTANCE hInstance, // handle of applicationinstance
LPCTSTRlpMenuName); // menu name string or menu-resource identifier
通过标准的CreateWindow()函数, 将菜单”ManiMenu”装载到该菜单句柄参数中:
// create the window
hwnd = CreateWindowEx(NULL, WINDOW_CLASS_NAME, “Sound”,
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 400, 400, NULL,
LoadMenu(hinstance, “MainMenu”), hinstance, NULL);
将菜单关联到窗口的最后一个方法是调用SetMenu()函数:
BOOL SetMenu( HWND hwnd, // handle of window to attach to
HMENUhMenu); // handle of menu
SetMenu()直接将该菜单关联到一个窗口上, 这个新菜单将优先于任何以前关联的菜单.例如:
// …
wnd.lpszMenuName = NULL;
// …
hwnd = CreateWindowEx(NULL, WINDOW_CLASS_NAME, “Sound”,
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 400, 400, NULL,
NULL, // handle to menu ,note it’s null.
hinstance, NULL);
//…
// load the menu resource
HMENU hMenu = LoadMenu(hinstance, “MainMenu”);
// attach the menu to the window
SetMenu(hwnd, hMemu);
3. 响应菜单事件的消息
在选中一个菜单项后放开鼠标时的消息传递,这指的是一个选择过程. 选择过程将一个WM_COMMAND消息传递到与该菜单关联的窗口的WinProc函数中. 指定的菜单项ID和其他各种数据存储在该消息的wparam和lparam中, 如下所示:
msg --- WM_COMMAND
LOWORD(lparam) ---- 发出消息的窗口句柄
wparam --- 选中的菜单项的ID
编译可能出现的错误:
DemoMenu.obj : error LNK2001: unresolved external symbol__imp__PlaySoundA@12
将winmm.lib添加到工程中, 过程: 工程->设置->连接->在工程选项中添加winmm.lib.
参考代码下载地址: http://download.csdn.net/detail/sund71/4426117