按钮本质上是一个窗口,对于普通窗口的创建流程
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
并且强转为(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);
}
效果
