创建菜单;MAKEINTRESOURCE;菜单加入窗口的两种方式

转自:http://blog.csdn.net/tcjiaan/article/details/8510260

MAKEINTRESOURCE是一个资源名转换的宏,这个宏是把一个数字类型转换指针类型的宏,它不存在释放的问题。

菜单加入窗口的两种方式

第一种是类级别的,也就是我们在设计窗口类时,直接指定给WNDCLASS结构的lpszMenuName成员,这样做意味着,在调用CreateWindow函数创建窗口时,无论你是否为窗口指定菜单,最终显示的窗口上都会有菜单,因为它是基于整个窗口类的。

[cpp]  view plain  copy
 print ?
  1. // 在这里把菜单附加上,成为类级别  
  2. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN);//整个菜单资源的ID,不是菜单项  
[cpp]  view plain  copy
 print ?
  1. HWND hm = CreateWindow(  
  2.     L"MainWd",  
  3.     L"我的应用程序",  
  4.     WS_OVERLAPPEDWINDOW,  
  5.     25,  
  6.     18,  
  7.     380,  
  8.     280,  
  9.     NULL,  
  10.     NULL,  
  11.     hthisInstance,  
  12.     NULL);  

这样在我们创建窗口时,哪怕你把hMenu参数设为NULL,最后显示的窗口都会有菜单,因为菜单是属于窗口类本身的。

 

另一种方式,就是不设置为类级别的菜单,而是在调用CreateWindow时指定给hMenu参数。

[cpp]  view plain  copy
 print ?
  1. HWND hm = CreateWindow(  
  2.     L"MainWd",  
  3.     L"我的应用程序",  
  4.     WS_OVERLAPPEDWINDOW,  
  5.     25,  
  6.     18,  
  7.     380,  
  8.     280,  
  9.     NULL,  
  10.     LoadMenu(hthisInstance,MAKEINTRESOURCE(IDR_MAIN)),  
  11.     hthisInstance,  
  12.     NULL);  

同时我们把设计窗口类时设置菜单的代码注释掉。

[cpp]  view plain  copy
 print ?
  1. // 在这里把菜单附加上,成为类级别  
  2. //wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN);//整个菜单资源的ID,不是菜单项  

然后,我们运行这个程序,它还是有菜单的。


方法一,用代码添加菜单

 

这种方法的思路是:首先在全局范围内定义一个HMENU的变量,用来保存窗口中菜单栏的句柄,根菜单(菜单栏)可以CreateMenu函数来创建,接着可以使用AppendMenu函数或者InsertMenuItem函数来创建菜单项。

句柄就是内存中各种资源的ID,比如图标,图片,字符串等。我们的菜单也是一种资源。

 

下面我写了一个函数,用来动态创建菜单。

[cpp]  view plain  copy
 print ?
  1. void CreateMyMenu()  
  2. {  
  3.     hRoot = CreateMenu();  
  4.     if(!hRoot)  
  5.         return;  
  6.     HMENU pop1 = CreatePopupMenu();  
  7.     AppendMenu(hRoot,  
  8.         MF_POPUP,  
  9.         (UINT_PTR)pop1,  
  10.         L"操作");  
  11.     // 一种方法是使用AppendMenu函数  
  12.     AppendMenu(pop1,  
  13.         MF_STRING,  
  14.         IDM_OPT1,  
  15.         L"飞机");  
  16.   
  17.     // 另一种方法是使用InsertMenuItem函数  
  18.     MENUITEMINFO mif;  
  19.     mif.cbSize = sizeof(MENUITEMINFO);  
  20.     mif.cch = 100;  
  21.     mif.dwItemData  = NULL;  
  22.     mif.dwTypeData = L"机关枪";  
  23.     mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;  
  24.     mif.fState = MFS_ENABLED;  
  25.     mif.fType = MIIM_STRING;  
  26.     mif.wID = IDM_OPT2;  
  27.   
  28.     InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);  
  29.   
  30. }  


hRoot是在外部定义的全局变量,保存菜单栏的标识。完整的代码如下:

[cpp]  view plain  copy
 print ?
  1. #include   
  2.   
  3. #define IDM_OPT1     301  
  4. #define IDM_OPT2     302  
  5.   
  6. HMENU hRoot;  
  7. void CreateMyMenu();//创建菜单  
  8.   
  9. LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
  10.   
  11.   
  12. int CALLBACK WinMain(HINSTANCE hInstance,  
  13.                     HINSTANCE hPrevInstance,  
  14.                     LPSTR cmdLine,  
  15.                     int nShow)  
  16. {  
  17.     CreateMyMenu();//创建菜单  
  18.     WCHAR* cn = L"Myapp";  
  19.     WNDCLASS wc={   };  
  20.     wc.hbrBackground = (HBRUSH)COLOR_WINDOW;  
  21.     wc.lpszClassName = cn;  
  22.     wc.style = CS_HREDRAW | CS_VREDRAW;  
  23.     wc.hInstance = hInstance;  
  24.     wc.lpfnWndProc = (WNDPROC)MyWinProce;  
  25.     RegisterClass(&wc);  
  26.     HWND hm = CreateWindow(cn,  
  27.         L"我的应用程序",  
  28.         WS_OVERLAPPEDWINDOW,  
  29.         20,  
  30.         15,  
  31.         420,  
  32.         360,  
  33.         NULL,  
  34.         hRoot,  
  35.         hInstance,  
  36.         NULL);  
  37.     if( hm == NULL )  
  38.         return 0;  
  39.     ShowWindow(hm,nShow);  
  40.     MSG msg;  
  41.     while(GetMessage(&msg,NULL,0,0))  
  42.     {  
  43.         TranslateMessage(&msg);  
  44.         DispatchMessage(&msg);  
  45.     }  
  46.   
  47.     return 0;  
  48. }  
  49.   
  50.   
  51. LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  52. {  
  53.     switch(msg)  
  54.     {  
  55.     case WM_DESTROY:  
  56.         //DestroyMenu(hRoot);  
  57.         PostQuitMessage(0);  
  58.         return 0;  
  59.     default:  
  60.         return DefWindowProc(hwnd, msg, wParam,lParam);  
  61.     }  
  62. }  
  63.   
  64. void CreateMyMenu()  
  65. {  
  66.     hRoot = CreateMenu();  
  67.     if(!hRoot)  
  68.         return;  
  69.     HMENU pop1 = CreatePopupMenu();  
  70.     AppendMenu(hRoot,  
  71.         MF_POPUP,  
  72.         (UINT_PTR)pop1,  
  73.         L"操作");  
  74.     // 一种方法是使用AppendMenu函数  
  75.     AppendMenu(pop1,  
  76.         MF_STRING,  
  77.         IDM_OPT1,  
  78.         L"飞机");  
  79.   
  80.     // 另一种方法是使用InsertMenuItem函数  
  81.     MENUITEMINFO mif;  
  82.     mif.cbSize = sizeof(MENUITEMINFO);  
  83.     mif.cch = 100;  
  84.     mif.dwItemData  = NULL;  
  85.     mif.dwTypeData = L"机关枪";  
  86.     mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;  
  87.     mif.fState = MFS_ENABLED;  
  88.     mif.fType = MIIM_STRING;  
  89.     mif.wID = IDM_OPT2;  
  90.   
  91.     InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);  
  92.   
  93. }  


 

 

方法二,通过编辑资源来添加菜单

上面的方法虽然创建了菜单,但你也看到了,是相当地不方便,所以,下面我重点介绍一下用资源编辑器来创建菜单资源。

在你的开发工具上,依次找到菜单项【视图】【资源视图】。

 

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

 

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

 

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

 

我们可以使用可视化视图来建立菜单,为了可以在代码中使用,给需要的菜单一个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相等,就知道用户点击了哪个菜单项。

所以,我们的程序代码现在应为:

[cpp]  view plain  copy
 print ?
  1. #include   
  2. #include "resource.h"  
  3.   
  4. LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
  5.   
  6.   
  7. int CALLBACK WinMain(HINSTANCE hInstance,  
  8.                     HINSTANCE hPrevInstance,  
  9.                     LPSTR cmdLine,  
  10.                     int nShow)  
  11. {  
  12.     WCHAR* cn = L"Myapp";  
  13.     WNDCLASS wc={   };  
  14.     wc.hbrBackground = (HBRUSH)COLOR_WINDOW;  
  15.     wc.lpszClassName = cn;  
  16.     wc.style = CS_HREDRAW | CS_VREDRAW;  
  17.     wc.hInstance = hInstance;  
  18.     wc.lpfnWndProc = (WNDPROC)MyWinProce;  
  19.     RegisterClass(&wc);  
  20.     HWND hm = CreateWindow(cn,  
  21.         L"我的应用程序",  
  22.         WS_OVERLAPPEDWINDOW,  
  23.         20,  
  24.         15,  
  25.         420,  
  26.         360,  
  27.         NULL,  
  28.         // 加载菜单资源  
  29.         LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAIN)),  
  30.         hInstance,  
  31.         NULL);  
  32.     if( hm == NULL )  
  33.         return 0;  
  34.     ShowWindow(hm,nShow);  
  35.     MSG msg;  
  36.     while(GetMessage(&msg,NULL,0,0))  
  37.     {  
  38.         TranslateMessage(&msg);  
  39.         DispatchMessage(&msg);  
  40.     }  
  41.   
  42.     return 0;  
  43. }  
  44.   
  45.   
  46. LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  47. {  
  48.     switch(msg)  
  49.     {  
  50.     case WM_COMMAND:  
  51.         {  
  52.             // 取出资源Id值  
  53.             // 并判断用户选择了哪个菜单项  
  54.             switch(LOWORD(wParam))  
  55.             {  
  56.             case IDM_PLANE:  
  57.                 MessageBox(hwnd,L"灰机来了。",L"提示",MB_OK);  
  58.                 break;  
  59.             case IDM_GUN:  
  60.                 MessageBox(hwnd,L"让炮弹飞。",L"提示",MB_OK);  
  61.                 break;  
  62.             case IDM_MT_GUN:  
  63.                 MessageBox(hwnd,L"山炮欲来风满楼。",L"提示",MB_OK);  
  64.                 break;  
  65.             default:  
  66.                 break;  
  67.             }  
  68.         }  
  69.         return 0;  
  70.     case WM_DESTROY:  
  71.         PostQuitMessage(0);  
  72.         return 0;  
  73.     default:  
  74.         return DefWindowProc(hwnd, msg, wParam,lParam);  
  75.     }  
  76. }  

在注册窗口类时,如要设置菜单,调用LoadMenu函数,第一个参数是当前程序实例的句柄,从WinMain的参数中获得,第二个参数是菜单的ID,因为这里要名字,字符串,而我们的ID都是数值,可通过MAKEINTRESOURCE宏转换。至于MessageBox函数就不用我介绍了。


 


你可能感兴趣的:(Windows程序编程)