Win32程序添加按钮和点击响应

⌚Time: 2023-01-08 21:10:21

👨‍💻Author: Jack Ge

按钮本质上是一个窗口,对于普通窗口的创建流程

1.设计窗口类2.注册窗口类3.创建窗口4.显示和更新窗口

按钮是系统定义好的窗口,因此就省略了创建和注册窗口类的过程,直接使用CreateWindow创建窗口

创建按钮时只需在CreateWindow的lpClassName参数也就是窗口类名设为"button"即可,"button"是按钮的预定义系统类名


void CreateWindowA(

  [in, optional]  lpClassName,//窗体类名

  [in, optional]  lpWindowName,//窗体名称

  [in]            dwStyle,//窗体风格

  [in]            x,//窗体水平位置

  [in]            y,//窗体垂直位置

  [in]            nWidth,//窗体宽度

  [in]            nHeight,//窗体高度

  [in, optional]  hWndParent,//父窗口句柄

  [in, optional]  hMenu,//菜单句柄

  [in, optional]  hInstance,//与窗体关联的实例句柄

  [in, optional]  lpParam

);

CreateWindow函数的倒数第三个参数hMenu为菜单句柄, 菜单句柄的作用是给窗口添加菜单。如果是创建子窗口,则该参数表示子窗口id,用来在程序中唯一标识该窗口。

对于按钮,是作为子窗体的,因此第三个参数dwStyle要加上两个标志:WS_CHILD(作为子窗体)和WS_VISIBLE(使窗体可见)。

除了按钮,其它预定义系统类名


Class   Description

Button  The class for a button.

ComboBox    The class for a combo box.

Edit    The class for an edit control.

ListBox The class for a list box.

MDIClient   The class for an MDI client window.

ScrollBar   The class for a scroll bar.

Static  The class for a static control.

窗口通过注册的WNDCLASS结构中回调函数来处理事件,按钮是一种特殊的窗体,并不需要提供单独的窗口回调函数,当按钮有事件产生时,会给父窗口消息处理程序发送一个WM_COMMAND消息,父窗口的接收到WM_COMMAND消息后,调用父窗口回调函数来处理

对于button按钮,可以定义一个id


#define IDC_BUTTON_0 1001

并且强转为(HMENU)类型传入参数


        CreateWindow("BUTTON",//按钮类名称,不可改变

            "Click me!", 

            WS_CHILD | WS_VISIBLE,

            100, 100, 100, 50,//按钮在界面上出现的位置

            hwnd,

            (HMENU)IDC_BUTTON_0,

            ((LPCREATESTRUCT)lParam)->hInstance,

            NULL);

如果有多个按钮,父窗口的回调函数在处理WM_COMMAND消息时,需要区分到底是哪个按钮被点击,WM_COMMAND消息会在消息附加信息wParam的低2字节中带上按钮的Id,按钮的id为按钮创建时的createwindow函数的倒数第三个参数hMenu,用来唯一标识程序中的按钮等控件。


    switch(wParam)

        {

        case IDC_BUTTON_0:

            MessageBox(NULL,"you clicked button0!","notice",MB_OK);

            return 0;

        case IDC_BUTTON_1:

            MessageBox(NULL,"you clicked button1!","notice",MB_OK);

            return 0;

        }

在父窗体创建完成后,变为可见之前,会触发WM_CREATE消息,可以在父窗体的WM_CREATE消息处理函数中创建按钮控件。

例子


#include <windows.h>

//定义按钮资源ID

#define IDC_BUTTON_0 1000

#define IDC_BUTTON_1 1001

//声明窗体过程回调函数

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

//win32函数入口

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)

{

    //设计窗体类

    const char CLASS_NAME[]  = "Sample Window Class";



    WNDCLASSA wc = { };



    wc.lpfnWndProc   = WindowProc;

    wc.hInstance     = hInstance;

    wc.lpszClassName = CLASS_NAME;

    //注册窗体类

    RegisterClassA(&wc);



    //创建窗体



    HWND hwnd = CreateWindowExA(

        0,                              // Optional window styles.

        CLASS_NAME,                     // Window class

        "Test Button",    // Window text

        WS_OVERLAPPEDWINDOW,            // Window style



        // Size and position

        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,



        NULL,       // Parent window    

        NULL,       // Menu

        hInstance,  // Instance handle

        NULL        // Additional application data

        );



    if (hwnd == NULL)

    {

        return 0;

    }

    //显示窗体

    ShowWindow(hwnd, nCmdShow);



    //启动消息循环



    MSG msg = { };

    while (GetMessage(&msg, NULL, 0, 0) > 0)

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }



    return 0;

}



LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    switch (uMsg)

    {

    case WM_CREATE://窗体建立消息

        //创建按钮

        CreateWindow("BUTTON",//按钮类名称,不可改变

            "Click me!",  

            WS_CHILD | WS_VISIBLE,

            100, 100, 100, 50,//按钮在界面上出现的位置

            hwnd,

            (HMENU)IDC_BUTTON_0,//按钮id

            ((LPCREATESTRUCT)lParam)->hInstance,

            NULL);

        CreateWindow("BUTTON",//按钮类名称,不可改变

            "Click me!",  

            WS_CHILD | WS_VISIBLE,

            400, 100, 100, 50,//按钮在界面上出现的位置

            hwnd,

            (HMENU)IDC_BUTTON_1,//按钮id

            ((LPCREATESTRUCT)lParam)->hInstance,

            NULL);

        return 0;

    case WM_COMMAND:

        switch(wParam)

        {

        case IDC_BUTTON_0://判断是按钮0的点击消息

            MessageBox(NULL,"you clicked button0!","notice",MB_OK);

            return 0;

        case IDC_BUTTON_1://判断是按钮1的点击消息

            MessageBox(NULL,"you clicked button1!","notice",MB_OK);

            return 0;

        }

        return DefWindowProc(hwnd, uMsg, wParam, lParam);

    case WM_DESTROY://窗体销毁消息

        PostQuitMessage(0);

        return 0;

    case WM_PAINT://重绘消息

        {

        PAINTSTRUCT ps;

        HDC hdc = BeginPaint(hwnd, &ps);



        // All painting occurs here, between BeginPaint and EndPaint.



        FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));



        EndPaint(hwnd, &ps);

        }

        return 0;

    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);

}


效果