本人独立博客http://xcroot.com/

Win 32 编程之按钮消息响应(代码小错误修复)

最近不想用MFC写东西了,有没有安装Qt和其他图形化开发环境,只能捣鼓API了。于是乎,就有了以下的学习--

首先,老套的创建个Windows窗口,由于自己有点小懒,就直接用Hello Word的源码了。

#include <windows.h>
#include <stdio.h>

// 窗口过程函数
LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(
                   HINSTANCE hInstance,         // handle to current instance
                   HINSTANCE hPrevInstance,     // handle to previous instance
                   LPSTR lpCmdLine,             // command line
                   int nCmdShow                 // show state
                   )

{
    // 窗口类
    WNDCLASS wndcls;
    wndcls.cbClsExtra = 0;                                          // 类附加内存
    wndcls.cbWndExtra = 0;                                          // 窗口附加内存
    wndcls.hbrBackground = (HBRUSH) GetStockObject(COLOR_WINDOW);    // 背景画刷句柄
    wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);                   // 窗口光标句柄
    wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);                       // 窗口图标句柄
    wndcls.hInstance = hInstance;                                   // 包含窗口过程函数的程序实例
    wndcls.lpfnWndProc = WinSunProc;                                // 只想窗口过程函数的指针
    wndcls.lpszClassName = "CRoot";                                // 窗口类名称
    wndcls.lpszMenuName = NULL;                                     // 菜单资源
    wndcls.style = CS_HREDRAW | CS_VREDRAW;                         // 窗口样式
    RegisterClass(&wndcls);

    // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄
    HWND hwnd;
    hwnd = CreateWindow(        // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL
        "CRoot",               // 窗口类名
        "Hello World",          // 窗口名字
        WS_CAPTION|WS_SYSMENU,    // 窗口样式
        CW_USEDEFAULT, CW_USEDEFAULT,                   // 窗口左上角坐标
        200, 120,               // 窗口宽高
        NULL,                   // 父窗口句柄
        NULL,                   // 窗口菜单句柄
        hInstance,              // 窗口所属应用程序实例
        NULL                    // WM_CREATE消息附加参数lParam传入的数据指针
        );

    // 显示及刷新窗口
    ShowWindow(hwnd, SW_SHOWNORMAL);
    UpdateWindow(hwnd);

    // 定义消息结构体
    MSG msg;
    while (GetMessage(  // WM_QUIT消息返回0 错误返回-1
        &msg,           // 指向消息的结构体
        NULL,           // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息
        0,              // 获取消息的最小值 通常为0
        0))             // 获取消息的最大值 都设为0表示接收所有消息
    {
        TranslateMessage(&msg);     // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出
        DispatchMessage(&msg);      // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理
    }
    return msg.wParam;
}

// 窗口过程函数
LRESULT CALLBACK WinSunProc(
    HWND hwnd,          // 窗口句柄
    UINT uMsg,          // 消息代码
    WPARAM wParam,      // 附加参数
    LPARAM lParam
)
{
    switch(uMsg)
    {
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar, "char code is %d", wParam);
        MessageBox(hwnd, szChar, "char", 0);
        break;

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    return 0;
}

然后,我们要在消息循环里面添加创建Button的代码,因为Button是一个子窗口,所以创建方式也如同创建窗口一样,使用CreateWindow()函数。

而,此窗口要一开始跟随父窗口出现,所以要在父窗口创建时创建该Button。嗯,所以要在窗口过程函数里面监听下WM_CREATE消息。

代码片段:

    switch(uMsg)
    {
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar, "char code is %d", wParam);
        MessageBox(hwnd, szChar, "char", 0);
        break;
    case WM_CREATE:
        CreateWindowEx(0,"Button","按钮1",WS_VISIBLE|WS_CHILD,0,0,100,50,hwnd,(HMENU)0,0,0);

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

这里要说明一下啦,一开始我也搞得晕晕乎乎,不知道怎么搞Button的消息事件,这里我们用Button的ID啦。先看下微软的MSDN关于CreateWindow()函数

HWND WINAPI CreateWindow(
  _In_opt_  LPCTSTR lpClassName,
  _In_opt_  LPCTSTR lpWindowName,
  _In_      DWORD dwStyle,
  _In_      int x,
  _In_      int y,
  _In_      int nWidth,
  _In_      int nHeight,
  _In_opt_  HWND hWndParent,
  _In_opt_  HMENU hMenu,
  _In_opt_  HINSTANCE hInstance,
  _In_opt_  LPVOID lpParam
);

关键点在参数HMENU hWndParent,第一眼一看是不是感觉像菜单?不错啦~确实在菜单中用到的。进一步看他的解释

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啦~

既然有标识,就好办啦,我们就判断是不是他,若是这个按钮,我们就让他响应相应的操作啦~~

但是怎么知道按钮被Click了呢?我们又得监听另一个消息WM_COMMAND,它有两个参数,其中一个就传输了所谓的控件ID

wParam

For a description of this parameter.

lParam

For a description of this parameter.

我们可以判断他如果是这个按钮的ID,我们就让他干某些事情。我们首先要转换下wParam的类型,否则和我们写的ID的类型不一样的。

case WM_COMMAND:
wmId    = LOWORD(wParam); 
wmEvent = HIWORD(wParam);
     switch (wmId)
     {
         case (0)://之前我们创建按钮时,写的ID为0
//功能代码 //....... break; //...更多代码 }

好了,整体框架差不多完工啦,自己再加下代码啥的就没问题了。在这里,我再次浪费下篇幅,给出完整代码:

关于wmId一开始写程序没有编译,因为逻辑错误,未有注意到,忘记声明他了。为了防止被default给忽略掉,我们把他写在switch(uMsg)之前。

 

 1 #include <windows.h>
 2 #include <stdio.h>
 3 #include <Windef.h>
 4 
 5 // 窗口过程函数
 6 LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 7 
 8 int WINAPI WinMain(
 9                    HINSTANCE hInstance,         // handle to current instance
10                    HINSTANCE hPrevInstance,     // handle to previous instance
11                    LPSTR lpCmdLine,             // command line
12                    int nCmdShow                 // show state
13                    )
14 
15 {
16     // 窗口类
17     WNDCLASS wndcls;
18     wndcls.cbClsExtra = 0;                                          // 类附加内存
19     wndcls.cbWndExtra = 0;                                          // 窗口附加内存
20     wndcls.hbrBackground = (HBRUSH) GetStockObject(COLOR_WINDOW);    // 背景画刷句柄
21     wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);                   // 窗口光标句柄
22     wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);                       // 窗口图标句柄
23     wndcls.hInstance = hInstance;                                   // 包含窗口过程函数的程序实例
24     wndcls.lpfnWndProc = WinSunProc;                                // 只想窗口过程函数的指针
25     wndcls.lpszClassName = "CRoot";                                // 窗口类名称
26     wndcls.lpszMenuName = NULL;                                     // 菜单资源
27     wndcls.style = CS_HREDRAW | CS_VREDRAW;                         // 窗口样式
28     RegisterClass(&wndcls);
29 
30     // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄
31     HWND hwnd;
32     hwnd = CreateWindow(        // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL
33         "CRoot",               // 窗口类名
34         "Hello World",          // 窗口名字
35         WS_CAPTION|WS_SYSMENU,    // 窗口样式
36         CW_USEDEFAULT, CW_USEDEFAULT,                   // 窗口左上角坐标
37         200, 120,               // 窗口宽高
38         NULL,                   // 父窗口句柄
39         NULL,                   // 窗口菜单句柄
40         hInstance,              // 窗口所属应用程序实例
41         NULL                    // WM_CREATE消息附加参数lParam传入的数据指针
42         );
43 
44     // 显示及刷新窗口
45     ShowWindow(hwnd, SW_SHOWNORMAL);
46     UpdateWindow(hwnd);
47 
48     // 定义消息结构体
49     MSG msg;
50     while (GetMessage(  // WM_QUIT消息返回0 错误返回-1
51         &msg,           // 指向消息的结构体
52         NULL,           // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息
53         0,              // 获取消息的最小值 通常为0
54         0))             // 获取消息的最大值 都设为0表示接收所有消息
55     {
56         TranslateMessage(&msg);     // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出
57         DispatchMessage(&msg);      // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理
58     }
59     return msg.wParam;
60 }
61 
62 // 窗口过程函数
63 LRESULT CALLBACK WinSunProc(
64     HWND hwnd,          // 窗口句柄
65     UINT uMsg,          // 消息代码
66     WPARAM wParam,      // 附加参数
67     LPARAM lParam
68 )
69 {
70     WORD wmId    = LOWORD(wParam);
71     //WORD wmEvent = HIWORD(wParam);
72     switch(uMsg)
73     {
74     /*case WM_CHAR:
75         char szChar[20];
76         sprintf(szChar, "char code is %d", wParam);
77         MessageBox(hwnd, szChar, "char", 0);
78         break;*/
79     case WM_CREATE:
80         CreateWindowEx(0,"Button","按钮1",WS_VISIBLE|WS_CHILD,0,0,70,40,hwnd,(HMENU)0,0,0);
81         break;
82     case WM_COMMAND:
83         switch (wmId)
84         {
85             case 0://(HMENU) 和创建中的id对应
86             //这里写你要让按钮实现的功能
87                 MessageBoxA(NULL,"Hello Button!","My TestProject",MB_OK);
88         }
89         break;
90 
91     default:
92         return DefWindowProc(hwnd, uMsg, wParam, lParam);
93     }
94 
95     return 0;
96 }
View Code

 

目前已经在GNU GCC Compiler成功!

 

posted @ 2013-12-21 23:40  CRoot  阅读(2176)  评论(0编辑  收藏  举报