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个妞,我一个都没换成,你的恋爱事业如此成 功。再说了,吕不韦临死前有教过秦始皇怎么统一中华吗?莫非秦始皇会说:以前没人统一过中原,我 怎么统一?最后他老人家照旧把六国给干掉了。