zoukankan      html  css  js  c++  java
  • 跟我一起玩Win32开发(12):使用控件——单选按钮

    今天,咱们还是接着玩“控件斗地主”,这是我原创的超级游戏,有益身心健康,玩一朝,十年少。

    哦,对,脑细胞极速运动了一下,想起了一个问题,这个破问题虽然网上有很多种解决方案,但是,并没有让所有人都解决问题。

    不知道大家有没有调用过LoadIconMetric函数,这个函数在静态库Comctl32.lib中有定义(当然,动态库也有),不过,创建项目的时候,默认并没有引用它的,于是,大家知道,解决调用的方法就是在代码中加上:

    [cpp] view plain copy
     
    1. #pragma comment(lib, "Comctl32.lib")  

    我一般习惯这种方法,这样不必去修改项目属性。但是,很多朋友说过,在Win 7以后的系统,依然没有成功,我也尝到了调用失败的“甜头”,我一直在想,这是为什么呢?

    于是,我又试了另一种方法,就是用LoadLibrary加载Comctl32.dll,然后通过函数指针去调用它:

    [cpp] view plain copy
     
    1. typedef LRESULT (WINAPI * pLoadICMT)(.......);  

    但结果还是没成功,GetProcAddress返回的地址为0,又一次尝到了失败带来的“刺激”感。

    直到某一天,我在写某程序时,从上一文中大家都看到,那个按钮的视觉风格和Win9x/2000差不多,似乎没有XP那种充满美学水准的效果。其实,这是因为我们的程序没有启用视觉效果,默认情况下,使用版本5中的控件,而要有XP以上的风格,是在版本6的控件内库中才有。

    当然方法可以很多人都知道,就是定义一个用于视觉效果的清单文件,本质是XML格式。不过我用的开发工具是VS 2005之后的版本,就不用弄个XML文件那么麻烦了,直接到MSDN上复制粘贴这段代码放到你的代码文件(.cpp)中,就是这个,直接抄过来就行了,适当的时候,要巧用MSDN上的资源。

    [cpp] view plain copy
     
    1. // 开启视觉效果 Copy from MSDN  
    2. #pragma comment(linker,""/manifestdependency:type='win32'   
    3. name='Microsoft.Windows.Common-Controls' version='6.0.0.0'   
    4. processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"")  

    version是版本号,要有好看的效果,记得要6,不要写用低版本的。processorArchitecture是处理器平台,x86或amd64,用*号最好,通杀。

    真是巧啊,原来这么一来,噗,LoadIconMetric也能调用了。总的来说,就是在代码文件加上以下内容:

    [cpp] view plain copy
     
    1. #include <CommCtrl.h> //包含头文件  
    2. // 导入静态库  
    3. #pragma comment(lib, "Comctl32.lib")  
    4. // 开启视觉效果 Copy from MSDN  
    5. #pragma comment(linker,""/manifestdependency:type='win32'   
    6. name='Microsoft.Windows.Common-Controls' version='6.0.0.0'   
    7. processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"")  


     

    这问题干掉了,开始今天的吹牛大行动。

    单选按钮,是的,在WinForm里面你肯定知道,RadioButto,复选框就是CheckBox。不过那个时候.NET还没那么猛,那个时代,就是玩VB6,所以我知道VB里面,单选按钮叫Option吧。

    然后找遍了Win32的控件库,怎么没见Radio和CheckBox,于是,我陷入了万分痛苦之中。不久后阅读MSDN文档,我就明白了,其实这两个玩意儿都是BUTTON类的,只是应用了不同的style罢了。

    好的,咱们先来弄一个单选的吧。

    [cpp] view plain copy
     
    1. case WM_CREATE:  
    2.     {  
    3.         CreateWindow(L"Button",L"这玩意儿好",  
    4.             BS_RADIOBUTTON | WS_CHILD | WS_VISIBLE,  
    5.             10,10,150,28,  
    6.             hwnd, (HMENU)IDC_RADBTN1,   
    7.             (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE),  
    8.             NULL);  
    9.     }  
    10.     return 0;  

    应用BS_RADIOBUTTON样式,就可以使按钮变成单选按钮,不过,别忘了WS_CHILD | WS_VISIBLE。

    运行一下。

    不过,当你点击它的时候,会发现它并不会选中,那是因为BS_RADIOBUTTON样式不会自动让它选上。我们换一种可以自动处理的样式,带AUTO打头的。

    就是用 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE,如下图的预览结果。

    接下来,我们多创建几个吧。

    [cpp] view plain copy
     
    1. /*-----------------------------------------------------------------*/  
    2. //控件ID  
    3. #define IDC_RADBTN1     50001  
    4. #define IDC_RADBTN2     50002  
    5. #define IDC_RADBTN3     50003  
    6. #define IDC_RADBTNBLUE      51001  
    7. #define IDC_RADBTNRED       51002  
    8. #define IDC_RADBTNGREEN     51003  
    9. /*-----------------------------------------------------------------*/  
    10. // 消息处理函数  
    11. LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
    12. {  
    13.     switch(msg)  
    14.     {  
    15.     case WM_CREATE:  
    16.         {  
    17.             // 获取当前实例句柄  
    18.             HINSTANCE hthisapp = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);  
    19.             // 纵坐标,控件将以此作为基准,  
    20.             // 排列时依次增加  
    21.             int yLoc = 0;  
    22.             // 用来显示文本  
    23.             yLoc += 10;  
    24.             CreateWindow(L"Static",L"请问你的性别是:",  
    25.                 SS_SIMPLE | WS_CHILD | WS_VISIBLE,  
    26.                 10,yLoc,160,18,  
    27.                 hwnd, NULL,   
    28.                 hthisapp,  
    29.                 NULL);  
    30.             // 第一组单选按钮  
    31.             yLoc += 22;  
    32.             CreateWindow(L"Button",L"男",  
    33.                 WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP,   
    34.                 12, yLoc, 60, 16,  
    35.                 hwnd,  
    36.                 (HMENU)IDC_RADBTN1,  
    37.                 hthisapp,NULL);  
    38.             yLoc += 20;  
    39.             CreateWindow(L"Button",L"女",  
    40.                 WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,   
    41.                 12,yLoc, 60, 16,  
    42.                 hwnd,(HMENU)IDC_RADBTN2,hthisapp,NULL);  
    43.             yLoc += 20;  
    44.             CreateWindow(L"Button",L"人妖",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,  
    45.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTN3,hthisapp,NULL);  
    46.             // 显示文本  
    47.             yLoc += 38;  
    48.             CreateWindow(L"Static",L"你喜欢哪一种颜色?",  
    49.                 WS_CHILD | WS_VISIBLE | SS_SIMPLE,  
    50.                 10,yLoc,150,18,hwnd,NULL,hthisapp,NULL);  
    51.             //第二组单选按钮  
    52.             yLoc += 22;  
    53.             CreateWindow(L"Button",L"蓝色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP,  
    54.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNBLUE,hthisapp,NULL);  
    55.             yLoc += 20;  
    56.             CreateWindow(L"Button",L"红色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,  
    57.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNRED,hthisapp,NULL);  
    58.             yLoc += 20;  
    59.             CreateWindow(L"Button",L"绿色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,  
    60.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNGREEN,hthisapp,NULL);  
    61.         }  
    62.         return 0;  
    63.     case WM_DESTROY:  
    64.         PostQuitMessage(0); //平安退出  
    65.         return 0;  
    66.     default:  
    67.         return DefWindowProc(hwnd,msg,wParam,lParam);  
    68.     }  
    69.     return 0;  
    70. }  

    在创建单选框中,为什么有些加了WS_GROUP样式,而有些未加呢?

    其实是这样的,既然单选按钮是单选的,那么,任何一个单选按钮都与其他的单选按钮是互斥的关系。所以,在同一个容器(本例是同一个窗口)中就需要把单选按钮进行分组。

    同一组中的单选按钮相互排斥,他的分组方法:

    顺序,以Tab键顺序为参考,这个不用我介绍,你随便打开一个窗口,然后多按几下Tab键你就懂了,如果不懂,那你真的无可救药了。

    凡是设置了WS_GROUP的单选框做为一组中的首元素,随后的所有单选按钮都和它在同一组,直到下一个设置了WS_GROUP样式的单选按钮。用上面的例子来说吧。

    性别一组中,第一个应用了WS_GROUP的是“男”,随后的“女”和“人妖”都与“男”在同一组,因为后面一个“蓝色”设置了WS_GROUP样式。所以,

    第一组为:男,女,人妖;

    第二组为:蓝色,红色,绿色。

    显然,用了BS_AUTORADIOBUTTON后,系统就会自动处理选择状态了。

    完整的代码清单如下:

    [cpp] view plain copy
     
      1. #include <Windows.h>  
      2. #include <WindowsX.h>  
      3. #include <CommCtrl.h> //包含头文件  
      4. // 导入静态库  
      5. #pragma comment(lib, "Comctl32.lib")  
      6. // 开启视觉效果 Copy from MSDN  
      7. #pragma comment(linker,""/manifestdependency:type='win32'   
      8. name='Microsoft.Windows.Common-Controls' version='6.0.0.0'   
      9. processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"")  
      10.   
      11. // 先声明一个WindowProc回调  
      12. LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
      13. // 入口点  
      14. int WINAPI wWinMain(HINSTANCE hTheApp, HINSTANCE hPrevApp, LPWSTR lpCmd, int nShow)  
      15. {  
      16.     PCWSTR cn = L"My"; // 窗口名  
      17.     PCWSTR tt = L"应用程序"; // 窗口标题  
      18.     // 设计窗口类  
      19.     WNDCLASS wc = { sizeof(WNDCLASS) };  
      20.     wc.hbrBackground = (HBRUSH)COLOR_WINDOW;  
      21.     wc.lpfnWndProc = WindowProc;  
      22.     wc.style = CS_HREDRAW | CS_VREDRAW;  
      23.     LoadIconMetric(hTheApp, IDI_APPLICATION, LIM_SMALL, &wc.hIcon);  
      24.     wc.lpszClassName = cn;  
      25.     wc.hInstance = hTheApp;  
      26.     RegisterClass(&wc); // 注册窗口类  
      27.     // 创建窗口  
      28.     HWND hwnd = CreateWindow(cn, tt,WS_OVERLAPPEDWINDOW,  
      29.         28,34,400,330,NULL,NULL,hTheApp,NULL);  
      30.     if( !hwnd)  
      31.     { /* 如果窗口创建失败, 
      32.          那继续执行也没有意义 
      33.         长痛不如短痛,结束吧。  
      34.       */  
      35.         return 0;  
      36.     }  
      37.     ShowWindow(hwnd,nShow); //显示窗口  
      38.     UpdateWindow(hwnd); //更新窗口  
      39.     // 消息循环  
      40.     MSG msg;  
      41.     while(GetMessage(&msg,NULL,0,0))  
      42.     {  
      43.         TranslateMessage(&msg);  
      44.         DispatchMessage(&msg); //调度消息到WindowProc回调  
      45.     }  
      46.     return 0;  
      47. }  
      48.   
      49. /*-----------------------------------------------------------------*/  
      50. //控件ID  
      51. #define IDC_RADBTN1         50001  
      52. #define IDC_RADBTN2         50002  
      53. #define IDC_RADBTN3         50003  
      54. #define IDC_RADBTNBLUE      51001  
      55. #define IDC_RADBTNRED       51002  
      56. #define IDC_RADBTNGREEN     51003  
      57. #define IDC_BTN_OK          1107 //确定按钮ID  
      58. /*-----------------------------------------------------------------*/  
      59. // 消息处理函数  
      60. LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
      61. {  
      62.     switch(msg)  
      63.     {  
      64.     case WM_CREATE:  
      65.         {  
      66.             // 获取当前实例句柄  
      67.             HINSTANCE hthisapp = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);  
      68.             // 纵坐标,控件将以此作为基准,  
      69.             // 排列时依次增加  
      70.             int yLoc = 0;  
      71.             // 用来显示文本  
      72.             yLoc += 10;  
      73.             CreateWindow(L"Static",L"请问你的性别是:",  
      74.                 SS_SIMPLE | WS_CHILD | WS_VISIBLE,  
      75.                 10,yLoc,160,18,  
      76.                 hwnd, NULL,   
      77.                 hthisapp,  
      78.                 NULL);  
      79.             // 第一组单选按钮  
      80.             yLoc += 22;  
      81.             CreateWindow(L"Button",L"男",  
      82.                 WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP,   
      83.                 12, yLoc, 60, 16,  
      84.                 hwnd,  
      85.                 (HMENU)IDC_RADBTN1,  
      86.                 hthisapp,NULL);  
      87.             yLoc += 20;  
      88.             CreateWindow(L"Button",L"女",  
      89.                 WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,   
      90.                 12,yLoc, 60, 16,  
      91.                 hwnd,(HMENU)IDC_RADBTN2,hthisapp,NULL);  
      92.             yLoc += 20;  
      93.             CreateWindow(L"Button",L"人妖",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,  
      94.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTN3,hthisapp,NULL);  
      95.             // 显示文本  
      96.             yLoc += 38;  
      97.             CreateWindow(L"Static",L"你喜欢哪一种颜色?",  
      98.                 WS_CHILD | WS_VISIBLE | SS_SIMPLE,  
      99.                 10,yLoc,150,18,hwnd,NULL,hthisapp,NULL);  
      100.             //第二组单选按钮  
      101.             yLoc += 22;  
      102.             CreateWindow(L"Button",L"蓝色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP,  
      103.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNBLUE,hthisapp,NULL);  
      104.             yLoc += 20;  
      105.             CreateWindow(L"Button",L"红色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,  
      106.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNRED,hthisapp,NULL);  
      107.             yLoc += 20;  
      108.             CreateWindow(L"Button",L"绿色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,  
      109.                 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNGREEN,hthisapp,NULL);  
      110.             // 创建一个确定按钮  
      111.             CreateWindow(L"Button",L"确定",WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  
      112.                 230,180,80,27,hwnd,(HMENU)IDC_BTN_OK,hthisapp,NULL);  
      113.         }  
      114.         return 0;  
      115.     case WM_DESTROY:  
      116.         PostQuitMessage(0); //平安退出  
      117.         return 0;  
      118.     default:  
      119.         return DefWindowProc(hwnd,msg,wParam,lParam);  
      120.     }  
      121.     return 0;  
      122. }  
  • 相关阅读:
    Java 进制转换
    k-近邻算法实例
    Java JTS & 空间数据模型
    Java中 &&与&,||与|的区别
    http https 区别
    四种DCOM错误的区别,0x80080005 0x800706be 0x80010105 0x
    OPC测试常用的OPCClient和OPCServer软件推荐
    关于TFS2010 远程无法创建团队项目的若干问题总结
    我对NHibernate的感受(4):令人欣喜的Interceptor机制
    我对NHibernate的感受(3):有些尴尬的集合支持
  • 原文地址:https://www.cnblogs.com/weekbo/p/8681914.html
Copyright © 2011-2022 走看看