zoukankan      html  css  js  c++  java
  • 跟我一起玩Win32开发(11):使用控件——先来耍一下按钮

    用户通过控件与应用程序交互,在吹牛之前,先介绍一个工具,这是官方的工具,使用它,你可以预览常用控件的外观、样式,以及对控进行操作时接收和发送哪些消息。下载地址如下:

    http://www.microsoft.com/en-us/download/details.aspx?id=4635

    我们可以把控件当成特殊的一类窗口,所以,创建控件与创建窗口一样,使用CreateWindow或CreateWindowEx函数,不过,在窗口样式上面记得用上以下两位帅哥:

    a、WS_CHILD:控件是放在我们的窗口上的,自然要作为窗口的子窗口,WS_CHILDWINDOW也一样,为了节约几个字母,用WS_CHILD吧。

    b、WS_VISIBLE:既然要使用控件,自然要让别人看得见。要想别人称赞你老婆漂亮,当然要先让别人见一见你老婆了,哈哈,不要想歪了。

    理论的东西,怎么说都是抽象的,咱们还是“所见即所得”吧。那么,到底在啥时候创建控件合适一点呢?一种方法是在WinMain方法中创建,把CreateWindow函数的hWndParent设置为窗口的句柄。

    俺这里用第二种方法,我们知道,在窗口创建后,显示之前,即CreateWindow函数返回之前,我们会收到WM_CREATE消息,我们响应它的号召,艰苦奋斗创建一个按钮。

    [cpp] view plain copy
     
    1. case WM_CREATE:  
    2.     {  
    3.         //创建按钮  
    4.         HWND hButton = CreateWindow(L"Button", L"有种就来点击我!", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    5.             35, 45, 160, 65, hwnd, NULL, hg_app, NULL);  
    6.     }  
    7.     return 0;  

    hg_app是我定义的一个全局变量,当前应用程序的句柄(HINSTANCE类型)。

    然后,运行一下,先看看效果再说吧。

    接下来,新的问题来了,按钮我是创建了,但怎么响应用户点击呢?其实,这按钮与菜单项一样,单击用户与她“亲密”接触后,我们的WindowProc会收到WM_COMMAND消息,和菜单一样。

    wParam的低字节位表示ID号,高字节位表示控件通知,比如用户单击了按钮,通知码为BN_CLICKED,这样我们就可以了解到用户具体对按钮干了什么。

    lParam中保存了控件的句柄。

    问题是,怎么设置控件的ID?我们看看CreateWindow的文档介绍。

    [cpp] view plain copy
     
    1. HWND WINAPI CreateWindow(  
    2.   _In_opt_  LPCTSTR lpClassName,  
    3.   _In_opt_  LPCTSTR lpWindowName,  
    4.   _In_      DWORD dwStyle,  
    5.   _In_      int x,  
    6.   _In_      int y,  
    7.   _In_      int nWidth,  
    8.   _In_      int nHeight,  
    9.   _In_opt_  HWND hWndParent,  
    10.   _In_opt_  HMENU hMenu,  
    11.   _In_opt_  HINSTANCE hInstance,  
    12.   _In_opt_  LPVOID lpParam  
    13. );  

    hMenu [in, optional] 
    Type: HMENU
    A handle to a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window. 

    简单地说,控件通常不需要菜单,所以,可以用这个参数来设置控件的ID,反正hMenu闲着也没事干,就给个ID它玩玩。ID号是一个整数,不过为了可读性,一般是声明一个宏,其实我们在资源编辑器中使用的资源ID(如IDM_FUCK)就是在resource.h中定义的宏的,既然叫ID了,你就知道它的值不要重复。

    我们也来模拟一下,在文件的前面(#include...后)也声明三个宏,分别标识三个按钮。

    [cpp] view plain copy
     
    1. #define IDB_ONE     3301  
    2. #define IDB_TWO     3302  
    3. #define IDB_THREE   3303  

    然后创建三个按钮:

    [cpp] view plain copy
     
    1.  case WM_CREATE:  
    2.   {  
    3.    //创建三个按钮  
    4.    CreateWindow(L"Button", L"按钮一", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    5.     35, 10, 120, 60, hwnd, (HMENU)IDB_ONE, hg_app, NULL);  
    6.    CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    7.     35, 80, 120, 60, hwnd, (HMENU)IDB_TWO, hg_app, NULL);  
    8.    CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    9.     35, 150, 120, 60, hwnd, (HMENU)IDB_THREE, hg_app, NULL);  
    10.   }  
    11.   return 0;  

    然后我们来响应WM_COMMAND消息。

    [cpp] view plain copy
     
    1. case WM_COMMAND:  
    2.     {  
    3.         switch(LOWORD(wParam))  
    4.         {  
    5.         case IDB_ONE:  
    6.             MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    7.             break;  
    8.         case IDB_TWO:  
    9.             MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    10.             break;  
    11.         case IDB_THREE:  
    12.             MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    13.             break;  
    14.         default:  
    15.             break;  
    16.         }  
    17.     }  
    18.     return 0;  


    看看效果。

    这时候,我希望,当我点击了按钮后,按钮上的文本变成“按钮X已点击”,该怎么做呢?Windows系统是基于消息机制的,所以,首先想到,向控件发送消息,要改变控件相关的文本,应当发送WM_SETTEXT消息。

    我们把上面的代码改一下。

    [cpp] view plain copy
     
    1. case WM_COMMAND:  
    2.     {  
    3.         switch(LOWORD(wParam))  
    4.         {  
    5.         case IDB_ONE:  
    6.             //MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    7.             SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第一个按鈕已点击");  
    8.             break;  
    9.         case IDB_TWO:  
    10.             //MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    11.             SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第二个按鈕已点击");  
    12.             break;  
    13.         case IDB_THREE:  
    14.             //MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    15.             SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第三个按鈕已点击");  
    16.             break;  
    17.         default:  
    18.             break;  
    19.         }  
    20.     }  
    21.     return 0;  


    前面我们知道,WM_COMMAND消息的lParam保存控件的句柄,所以,我们传给SendMessage的第一个参数是操作目标的句柄,注意,这里不要传WindowProc回调中的参数,因为我们现在要操作的对象是按钮,不是窗口,WindowProc传进到的句柄是指我们注册的窗口,因为我们在WNDCLASS中已经设定了该WindowProc函数。

    要对按钮进行操作,应当使用WM_COMMAND的lParam中包含的值,强制转换为HWND。

    运行结果如下图所示。

    完整的示例如下:

    [cpp] view plain copy
     
    1. #include <Windows.h>  
    2. #include <WinNT.h>  
    3. //#include "resource.h"  
    4.   
    5. #define IDB_ONE     3301  
    6. #define IDB_TWO     3302  
    7. #define IDB_THREE   3303  
    8.   
    9. LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
    10.   
    11. LPCWSTR lps_cl = L"MyApp";//类名  
    12. LPCWSTR wd_text = L"超级应用";//窗口标题  
    13. HINSTANCE hg_app;//全局实例句柄  
    14.   
    15. int WINAPI wWinMain(HINSTANCE hThisApp,  
    16.     HINSTANCE hPrevApp,  
    17.     LPWSTR lpCmd,  
    18.     int nShow)  
    19. {  
    20.     WNDCLASSEX wc = { };  
    21.     wc.cbSize = sizeof(WNDCLASSEX);  
    22.     wc.hbrBackground = (HBRUSH)COLOR_WINDOW;  
    23.     wc.hInstance = hThisApp;  
    24.     wc.lpfnWndProc = (WNDPROC)WindowProc;  
    25.     wc.lpszClassName = lps_cl;  
    26.     wc.style = CS_HREDRAW | CS_VREDRAW;  
    27.     RegisterClassEx(&wc);  
    28.     HWND hwnd = CreateWindowEx(WS_EX_WINDOWEDGE,  
    29.                     lps_cl,  
    30.                     wd_text,  
    31.                     WS_OVERLAPPEDWINDOW,  
    32.                     20,  
    33.                     25,  
    34.                     400,  
    35.                     300,  
    36.                     NULL,  
    37.                     NULL,  
    38.                     hThisApp,  
    39.                     NULL);  
    40.     if(hwnd == NULL)  
    41.         return -1;  
    42.     ShowWindow(hwnd, nShow);  
    43.     UpdateWindow(hwnd);  
    44.     hg_app = hThisApp;  
    45.   
    46.     MSG msg;  
    47.     while(GetMessage(&msg,NULL,0,0))  
    48.     {  
    49.         TranslateMessage(&msg);  
    50.         DispatchMessage(&msg);  
    51.     }  
    52.     return 0;  
    53. }  
    54.   
    55. LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
    56. {  
    57.     switch(msg)  
    58.     {  
    59.     case WM_DESTROY:  
    60.         PostQuitMessage(0);  
    61.         return 0;  
    62.     case WM_CREATE:  
    63.         {  
    64.             //创建三个按钮  
    65.             CreateWindow(L"Button", L"按钮一", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    66.                 35, 10, 160, 60, hwnd, (HMENU)IDB_ONE, hg_app, NULL);  
    67.             CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    68.                 35, 80, 160, 60, hwnd, (HMENU)IDB_TWO, hg_app, NULL);  
    69.             CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    70.                 35, 150, 160, 60, hwnd, (HMENU)IDB_THREE, hg_app, NULL);  
    71.         }  
    72.         return 0;  
    73.     case WM_COMMAND:  
    74.         {  
    75.             switch(LOWORD(wParam))  
    76.             {  
    77.             case IDB_ONE:  
    78.                 //MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    79.                 SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第一个按鈕已点击");  
    80.                 break;  
    81.             case IDB_TWO:  
    82.                 //MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    83.                 SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第二个按鈕已点击");  
    84.                 break;  
    85.             case IDB_THREE:  
    86.                 //MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
    87.                 SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第三个按鈕已点击");  
    88.                 break;  
    89.             default:  
    90.                 break;  
    91.             }  
    92.         }  
    93.         return 0;  
    94.     default:  
    95.         return DefWindowProc(hwnd,msg,wParam,lParam);  
    96.     }  
    97.     return 0;  
    98. }  


     

  • 相关阅读:
    Linux安装jdk
    VUE和Element:Vue和Element基础使用,综合案例学生列表实现
    jQuery-css(border)样式内容火狐无法获取而谷歌可以获取问题问题
    Ajax:原生js实现Ajax,jQuery的get/post方式实现Ajax,jQuery的通用方式实现Ajax;JSON转换;搜索联想;瀑布流分页,点击按钮分页
    常用正则表达式大全,如何写出高效率的正则表达式?
    JQuery:JQuery基本语法,JQuery选择器,JQuery DOM,综合案例 复选框,综合案例 随机图片
    操作系统的一些概念题(1)
    谓词逻辑与归结原理的一些概念题
    模拟退火 Simulated annealing
    遗传算法Genetic Algorithm
  • 原文地址:https://www.cnblogs.com/weekbo/p/8681911.html
Copyright © 2011-2022 走看看