Win32开拓入门(4) 建设菜单
副标题#e#
我们虽然知道 ,此刻,在实际开拓中必定不会像我这样写Win32措施的,你看,连个WinMain都要N行代码。但许多人 不大白什么叫进修,什么叫摸索。实际上,凡是能用于实际开拓中的能力只是占我们对客观世界的认识 总和不到20%,所以,假如你有乐趣计较一下,预计有80%的常识你不知道用到那边去了。就算我们此后 不会把Win32措施投入到实际操纵中,然而假如你相识过这对象,你会发明许多时候对我们是有辅佐的 。
哪怕只是简朴认识一下Win32的一些道理,相信对付日后编程的进修和生长,是有益处的。
为了提高误人后辈的结果,上面我说了几段F话,下面开始本日的正题。
要在窗口上添 加菜单,虽然你大概会研究出N种要领,不外,这里我说两种,一种相当巨大,另一种稍微简朴。
要领一,用代码添加菜单
这种要领的思路是:首先在全局范畴内界说一个HMENU的变量 ,用来生存窗口中菜单栏的句柄,根菜单(菜单栏)可以CreateMenu函数来建设,接着可以利用 AppendMenu函数可能InsertMenuItem函数来建设菜单项。
句柄就是内存中各类资源的ID,好比 图标,图片,字符串等。我们的菜单也是一种资源。
下面我写了一个函数,用来动态建设菜单 。
void CreateMyMenu()
{
hRoot = CreateMenu();
if(!hRoot)
return;
HMENU pop1 = CreatePopupMenu();
AppendMenu(hRoot,
MF_POPUP,
(UINT_PTR)pop1,
L"操纵");
// 一种要领是利用AppendMenu函数
AppendMenu(pop1,
MF_STRING,
IDM_OPT1,
L"飞机");
// 另一种要领是利用InsertMenuItem函数
MENUITEMINFO mif;
mif.cbSize = sizeof(MENUITEMINFO);
mif.cch = 100;
mif.dwItemData = NULL;
mif.dwTypeData = L"构造枪";
mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
mif.fState = MFS_ENABLED;
mif.fType = MIIM_STRING;
mif.wID = IDM_OPT2;
InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);
}
#p#副标题#e#
hRoot是在外部界说的全局变量,生存菜单栏的标识。完整的代码如下:
#include
<Windows.h>
#define IDM_OPT1 301
#define IDM_OPT2 302
HMENU hRoot;
void CreateMyMenu();//建设菜单
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int CALLBACK WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR cmdLine,
int nShow)
{
CreateMyMenu();//建设菜单
WCHAR* cn = L"Myapp";
WNDCLASS wc={ };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = cn;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)MyWinProce;
RegisterClass(&wc);
HWND hm = CreateWindow(cn,
L"我的应用措施",
WS_OVERLAPPEDWINDOW,
20,
15,
420,
360,
NULL,
hRoot,
hInstance,
NULL);
if( hm == NULL )
return 0;
ShowWindow(hm,nShow);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
//DestroyMenu(hRoot);
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam,lParam);
}
}
void CreateMyMenu()
{
hRoot = CreateMenu();
if(!hRoot)
return;
HMENU pop1 = CreatePopupMenu();
AppendMenu(hRoot,
MF_POPUP,
(UINT_PTR)pop1,
L"操纵");
// 一种要领是利用AppendMenu函数
AppendMenu(pop1,
MF_STRING,
IDM_OPT1,
L"飞机");
// 另一种要领是利用InsertMenuItem函数
MENUITEMINFO mif;
mif.cbSize = sizeof(MENUITEMINFO);
mif.cch = 100;
mif.dwItemData = NULL;
mif.dwTypeData = L"构造枪";
mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
mif.fState = MFS_ENABLED;
mif.fType = MIIM_STRING;
mif.wID = IDM_OPT2;
InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);
}

要领二,通过编辑资源来添加菜单
上面的要领固然建设了菜单,但你 也看到了,是相内地不利便,所以,下面我重点先容一下用资源编辑器来建设菜单资源。
在你 的开拓东西上,依次找到菜单项【视图】【资源视图】。

在资源视图中,右击项目根节点,从弹出的菜单中选择【添加】【资源】。

在随后弹出的对话框中,选择Menu,单击右边的“新建”按钮。

可以通过属性窗口来重定名菜单的ID。

#p#分页标题#e#
我们可以利用可视化视图来成立菜单,为了可以在代码中利用,给需要的菜单一个ID,这个 名字你可以本身喜欢,只是习用的是以IDM_开头,意思是Menu ID,好比IDC开头的,意思是Control ID 等等。

编辑好之后,生存,在【办理方案资源打点器】中你会看到一个resource.h 文件,其实我们为资源界说的ID都以宏的形式声明的,不信你打开看看。

资源ID都是数字,只是为它界说个名字,利便识别而已,就仿佛人们平时只叫你的名字可能 奶名,你见过谁会叫你的身份证号码的?
开拓东西生成的ID有时候会有问题,可能有些ID我们 在措施中没用上,假如你以为它们留在代码文件中会影响市容的话,你可以这样:
1、在【资源 视图】窗口中,右击,从弹出的快捷菜单中选择【资源标记…】,弹出一个窗口,这里可以看到应用 措施中的资源ID列表,以及哪些ID已被利用,可是,这个窗口中显示的内容,有时候禁绝确,有些ID明 明没有被利用,它右边却打上了勾。
这里可以修改ID的值,也可以新建资源ID,所以,你也可 以在这里预先为资源分派ID,然后在属性窗口配置资源的标识时,从下拉列表中选择指定的ID。资源ID 的名字和数值不能反复,可是,差异的资源是可以利用同一个资源ID的。譬喻,凡是在应用措施中,某 些菜单项的成果和东西栏上的按钮是一一对应的,成果沟通,这种环境下,我们可以思量让它们共用一 个ID。
2、你可以直接打开resource.h头文件,直接在上面修改。
响应菜单呼吁
当用户单击某个菜单项后,窗口处理惩罚措施(WindowProc)会收到一条WM_COMMAND动静,它的两个附加参 数如下:

在收到WM_COMMAND后,我们可以用LOWORD取得它的低数位, 上表中已经说明,wParam的低位值暗示菜单的资源ID,我们通过它的值与哪个菜单的ID相等,就知道用 户点击了哪个菜单项。
所以,我们的措施代码此刻应为:
#include
<Windows.h>
#include "resource.h"
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int CALLBACK WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR cmdLine,
int nShow)
{
WCHAR* cn = L"Myapp";
WNDCLASS wc={ };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = cn;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)MyWinProce;
RegisterClass(&wc);
HWND hm = CreateWindow(cn,
L"我的应用措施",
WS_OVERLAPPEDWINDOW,
20,
15,
420,
360,
NULL,
// 加载菜单资源
LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAIN)),
hInstance,
NULL);
if( hm == NULL )
return 0;
ShowWindow(hm,nShow);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_COMMAND:
{
// 取出资源Id值
// 并判定用户选择了哪个菜单项
switch(LOWORD(wParam))
{
case IDM_PLANE:
MessageBox(hwnd,L"灰机来了。",L"提示",MB_OK);
break;
case IDM_GUN:
MessageBox(hwnd,L"让炮弹飞。",L"提示",MB_OK);
break;
case IDM_MT_GUN:
MessageBox(hwnd,L"山炮欲来风满楼。",L"提示",MB_OK);
break;
default:
break;
}
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam,lParam);
}
}
#p#分页标题#e#
在注册窗口类时,如要配置菜单,挪用LoadMenu函数,第一个参数是当前措施实例的句柄, 从WinMain的参数中得到,第二个参数是菜单的ID,因为这里要名字,字符串,而我们的ID都是数值, 可通过MAKEINTRESOURCE宏转换。至于MessageBox函数就不消我先容了。

好了,我们的应用措施已经建设了菜单了。
呵,有人说我的编程进修要领很怪异,其 实,我们何苦要墨守陈规呢,范围在定势思维中呢?枯躁无味的对象,你可以工钱地让它变得布满兴趣 ,要害是你的心态而已。这让我想起,以前某同学A跟我接头两个问题:
1、我的措施只想生存 用户的一些利用配置,用数据库没须要,写注册不环保;
2、我有一个dll类库,我但愿最后我 的措施既可以引用它,但同时只生成一个exe文件,能做到吧。
我就说了,问题一好办,你界说 一个存放配置项的类,把它直接举办XML序列化和反序列化就完事了,这既能生存数据,又可以封装对 象。假如不想让别人看到XML文件中的内容,就把它用DES算法加密/解密;而第二个问题,你把dll文件 当成资源嵌入到措施的资源文件中,运行时假如要用到类库的类,那就把它反射出来,动态挪用就行了 。
然后他说,这仿佛没有人这样做,老师也没教过。
我说:靠,你老爸小时候教过你泡 妞吗?你一上大学怎么就学会了泡妞?四年大学还换了N个妞,我一个都没换成,你的恋爱事业如此成 功。再说了,吕不韦临死前有教过秦始皇怎么统一中华吗?莫非秦始皇会说:以前没人统一过中原,我 怎么统一?最后他老人家照旧把六国给干掉了。