具有单选标记的菜单;auto关键字;CheckMenuRadioItem函数

来源:互联网 发布:python怎么发音 编辑:程序博客网 时间:2024/05/29 06:44

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

CheckMenuRadioItem函数

The CheckMenuRadioItem function checks a specified menu item and makes it a radio item. At the same time, the function clears all other menu items in the associated group and clears the radio-item type flag for those items.

BOOL CheckMenuRadioItem(  HMENU hmenu,   // handle to menu  UINT idFirst,  // identifier or position of first item  UINT idLast,   // identifier or position of last item  UINT idCheck,  // identifier or position of menu item  UINT uFlags    // function options);

Parameters

hmenu
[in] Handle to the menu that contains the group of menu items.要在其子项中设置的单选的菜单的句柄
idFirst
[in] Identifier or position of the first menu item in the group.第二个参数和第三个参数指定合并为一个组的ID范围,在这个范围内的菜单项被看人为同一组,这一组中,每一次只能有一项被checked,
idLast
[in] Identifier or position of the last menu item in the group.
idCheck
[in] Identifier or position of the menu item to check.第四个参数就指定在这组项中哪一个被选中
uFlags
[in] Value specifying the meaning of idFirst, idLast, and idCheck. If this parameter is MF_BYCOMMAND, the other parameters specify menu item identifiers. If it is MF_BYPOSITION, the other parameters specify the menu item positions.最后一个参数决定是用ID来标识还用从0开始的索引。

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, use theGetLastError function.

Remarks

The CheckMenuRadioItem function sets the MFT_RADIOCHECK type flag and the MFS_CHECKED state for the item specified byidCheck and, at the same time, clears both flags for all other items in the group. The selected item is displayed using a bullet bitmap instead of a check-mark bitmap.

For more information about menu item type and state flags, see the MENUITEMINFO structure.

Requirements

今天,我们的目的是,想要实现下图中的这种菜单效果。

就是一种类似单选按钮的菜单,多个菜单项中,同时只有一个会被选中。

首先,我们在资源编辑器中,设计一个菜单资源。这个资源编辑器在管理资源ID的时候,有些问题,有时候不同步更新,有时候会保存不到,反正就会混乱。如果遇到问题,你可以先把菜单设计好,接着打开resource.h,手动把这些ID和它的值改一下。为了使这三个菜单项能形成一个组,必须让它们的ID值是连续的,比如我这里让它们分别为501,502,503。

 

101指的是整个菜单资源,后三个都是子菜单项。如果想更保险的话,可以在【解决方案资源管理器】中右击资源文件(.rc结尾),选择【查看代码】,然后检查一下是否正确就可以了。

 

现在菜单弄好了,下面我们来了解一下把菜单添加到窗口的两个类型。

第一种是类级别的,也就是我们在设计窗口类时,直接指定给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,不是菜单项  

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

 

接着,我们把CreateWindow的hMenu参数设置为NULL,

[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.     NULL,  
  12.     hthisInstance,  
  13.     NULL);  

看看这时候运行程序,还能不能看到菜单。



现在就看不到菜单了,这两种加载菜单的方式,就区别在这里。

 

要为菜单实现单选标记,调用CheckMenuRadioItem函数,第一个参数是要在其子项中设置的单选的菜单的句柄,第二个参数和第三个参数指定合并为一个组的ID范围,在这个范围内的菜单项被看人为同一组,这一组中,每一次只能有一项被checked,第四个参数就指定在这组项中哪一个被选中,最后一个参数决定是用ID来标识还用从0开始的索引。

但是,我们在改变菜单项单选状态前,必须获得【水果】弹出菜单的句柄。

我们先来看一下,一般菜单栏的层次结构。

它就像一个树形结构,一层一层往下展开,上图中,红色矩形画的部分是菜单的根,即整个菜单栏,蓝色矩形标注的是菜单栏的下一级,弹出菜单,如【文件】、【编辑】、【视图】这些,它们一般只负责弹出子项列表,自身不响应用户选择命令,这也是我们在资源编辑器中设计菜单时,不需要给它们ID号的原因。

在【文件】下面又有了项,如图中黄色矩形标注的地方,如【新建】、【打开】。

 

知道这个后,我们的思路就有了。

1、调用GetMenu( 窗口句柄 )获取窗口中菜单栏的句柄;

2、调用GetSubMenu(  菜单栏句柄,0 )获得【水果】弹出菜单的句柄,0表示菜单栏中的第一个元素,如果第二个就是1,我们的弹出菜只有【水果】一项;

3、调用CheckMenuRadioItem函来来Check菜单。

 

因为我们是在响应WM_COMMAND消息时作出响应的,所以这些代码应写在WindowProc中。

[cpp] view plain copy
 print?
  1. LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     // 获取窗口上的整个菜单栏的句柄  
  4.     HMENU hmm = GetMenu(hwnd);  
  5.     // 获取第一个弹出菜单,即[水果]菜单  
  6.     HMENU hfmn = GetSubMenu(hmm, 0);  
  7.     switch(msg)  
  8.     {  
  9.     case WM_COMMAND:  
  10.         {  
  11.         .......  

菜单句柄是HMENU类型,所以GetMenu和GetSubMenu函数都返回HMENU类型的值。其实,这里我给大家推荐一个技巧,就是使用auto关键字,我们无需管它函数什么,统一用auto关键字,它会根据代码上下文推断数据类型,就像C#里面的var声明变量一样。所以,我们上面的代码可以改为:

[cpp] view plain copy
 print?
  1. LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     // 获取窗口上的整个菜单栏的句柄  
  4.     auto hmm = GetMenu(hwnd);  
  5.     // 获取第一个弹出菜单,即[水果]菜单  
  6.     auto hfmn = GetSubMenu(hmm, 0);  
  7.     switch(msg)  
  8.     {  
  9.     case WM_COMMAND:  
  10.         {  
  11.          ........  


然后,我们响应命令消息。

[cpp] view plain copy
 print?
  1. switch(msg)  
  2. {  
  3. case WM_COMMAND:  
  4.     {  
  5.         //判断用户选了哪个菜单  
  6.         switch(LOWORD(wParam))  
  7.         {  
  8.         case IDM_APPLE:  
  9.             CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_APPLE, MF_BYCOMMAND);  
  10.             MessageBox(hwnd,L"你选择了苹果。",L"提示",MB_OK);  
  11.             break;  
  12.         case IDM_PEAR:  
  13.             CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_PEAR, MF_BYCOMMAND);  
  14.             MessageBox(hwnd,L"你选择了梨子。", L"提示", MB_OK);  
  15.             break;  
  16.         case IDM_BANANA:  
  17.             CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_BANANA, MF_BYCOMMAND);  
  18.             MessageBox(hwnd, L"你选择了香蕉。", L"提示", MB_OK);  
  19.             break;  
  20.         }  
  21.     }  
  22.     return 0;  


这样就得到单选菜单的效果了。下面是完整的代码清单。

[cpp] view plain copy
 print?
  1. #include <Windows.h>  
  2. #include "resource.h"  
  3.   
  4. // 声明消息处理函数  
  5. LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
  6.   
  7. //入口点  
  8. int WINAPI WinMain(  
  9.     HINSTANCE hthisInstance,//当前实例句柄  
  10.     HINSTANCE hPrevInstance,//钱一个实例句柄,一般不使用  
  11.     LPSTR cmdline,//命令行参数  
  12.     int nShow)//窗口的显示方式  
  13. {  
  14.     // 设计窗口类  
  15.     WNDCLASS wc = { };  
  16.     wc.lpszClassName = L"MainWd";  
  17.     wc.hInstance  = hthisInstance;  
  18.     wc.lpfnWndProc = WindowMainProc;  
  19.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);  
  20.     // 在这里把菜单附加上,成为类级别  
  21.     //wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN);//整个菜单资源的ID,不是菜单项  
  22.     // 让窗口自动重绘  
  23.     wc.style = CS_HREDRAW | CS_VREDRAW;  
  24.     // 注册窗口类  
  25.     RegisterClass(&wc);  
  26.     // 创建窗口  
  27.     HWND hm = CreateWindow(  
  28.         L"MainWd",  
  29.         L"我的应用程序",  
  30.         WS_OVERLAPPEDWINDOW,  
  31.         25,  
  32.         18,  
  33.         380,  
  34.         280,  
  35.         NULL,  
  36.         LoadMenu(hthisInstance,MAKEINTRESOURCE(IDR_MAIN)),  
  37.         hthisInstance,  
  38.         NULL);  
  39.     if(hm == NULL)  
  40.         return 0;  
  41.     // 显示窗口  
  42.     ShowWindow(hm, SW_SHOW);  
  43.     // 消息循环  
  44.     MSG msg;  
  45.     while(GetMessage(&msg, NULL, 0, 0))  
  46.     {  
  47.         TranslateMessage(&msg);  
  48.         DispatchMessage(&msg);  
  49.     }  
  50.     return 0;  
  51. }  
  52.   
  53. LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  54. {  
  55.     // 获取窗口上的整个菜单栏的句柄  
  56.     auto hmm = GetMenu(hwnd);  
  57.     // 获取第一个弹出菜单,即[水果]菜单  
  58.     auto hfmn = GetSubMenu(hmm, 0);  
  59.     switch(msg)  
  60.     {  
  61.     case WM_COMMAND:  
  62.         {  
  63.             //判断用户选了哪个菜单  
  64.             switch(LOWORD(wParam))  
  65.             {  
  66.             case IDM_APPLE:  
  67.                 CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_APPLE, MF_BYCOMMAND);  
  68.                 MessageBox(hwnd,L"你选择了苹果。",L"提示",MB_OK);  
  69.                 break;  
  70.             case IDM_PEAR:  
  71.                 CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_PEAR, MF_BYCOMMAND);  
  72.                 MessageBox(hwnd,L"你选择了梨子。", L"提示", MB_OK);  
  73.                 break;  
  74.             case IDM_BANANA:  
  75.                 CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_BANANA, MF_BYCOMMAND);  
  76.                 MessageBox(hwnd, L"你选择了香蕉。", L"提示", MB_OK);  
  77.                 break;  
  78.             }  
  79.         }  
  80.         return 0;  
  81.     case WM_DESTROY:  
  82.         PostQuitMessage(0);  
  83.         return 0;  
  84.     default:  
  85.         return DefWindowProc(hwnd, msg, wParam, lParam);  
  86.     }  
  87. }  

0 0
原创粉丝点击