zoukankan      html  css  js  c++  java
  • 跟我一起玩Win32开发(5):具有单选标记的菜单

    帅哥们,美女们,下午好,我又来误人子弟,请做好准备。

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

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

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

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

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

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

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

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

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

    [cpp] view plain copy
     
    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
     
    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
     
    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
     
    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
     
      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. }  
  • 相关阅读:
    CSS3—— 2D转换 3D转换 过渡 动画
    CSS3——边框 圆角 背景 渐变 文本效果
    CSS3——表单 计数器 网页布局 应用实例
    CSS3——提示工具 图片廓 图像透明 图像拼接技术 媒体类型 属性选择器
    CSS3——对齐 组合选择符 伪类 伪元素 导航栏 下拉菜单
    CSS3——分组和嵌套 尺寸 display显示 position定位 overflow float浮动
    CSS3——盒子模型 border(边框) 轮廓(outline)属性 margin外边距 padding填充
    Eclipse连接数据库报错Local variable passwd defined in an enclosing scope must be final or effectively final
    数据库——单表查询
    数据库——添加,修改,删除
  • 原文地址:https://www.cnblogs.com/weekbo/p/8681895.html
Copyright © 2011-2022 走看看