特殊说明:版权归个人所有,请勿转载,谢谢合作。
按钮控件是一种接受用户命令的控件,通常可以响应鼠标单击或双击事件的矩形窗口。按钮命令是通过鼠标或键盘的操作来响应相应的事件,按钮中可以显示文本或位图。根据按钮实现功能的不同分为:命令按钮(Push Button)、复选框(Check Box)、单选按钮(Radio Button)、分组框(Group Box)以及自绘按钮(Owner-draw Button)。
按钮控件是不能接受用户的输入,只能响应相应的消息,如表10.1所示,描述了按钮控件的通知消息。
- 表10.1 按钮控件的通知消息
| 消息 | 描述 |
| BN_CLICKED | 按钮单击消息 |
| BN_DOUBLECLICKED | 按钮双击消息 |
按钮控件通过CreateWindow或CreateWindowEx函数创建,下面以CreateWindow函数为列,创建一个通用命令按钮控件。
// 创建按钮
g_hButtonWnd = CreateWindow("BUTTON", "MyButton",
WS_CHILD | WS_VISIBLE, 50+80+10, 50, 100, 20,
hWnd, NULL, g_hIns, NULL);
除了标准按钮,可以通过CreateWindow函数来创建不同风格的按钮(如:单选、多选按钮等),通过第三个参数dwStyle来指定,具体可指定的风格(可以是风格的组合)如表10.2所示。
- 表10.2 按钮控件风格
| 风格 | 描述 |
| BS_AUTOCHECKBOX | 同BS_CHECKBOX,创建一个自动选中的复选按钮,只有在复选框里设置值才起作用 |
| BS_AUTORADIOBUTTON | 同BS_RADIOBUTTON,创建一个自动选中的单选按钮 |
| BS_AUTO3STATE | 同BS_3STATE,创建自动的三态按钮 |
| BS_CHECKBOX | 创建一个复选按钮 |
| BS_DEFPUSHBUTTON | 创建默认选中的按键按钮,当用户按下Enter键时,则表示选择该按键按钮 |
| BS_GROUPBOX | 创建按钮组合框,当创建一组单选按钮或者复选按钮时,首先需要创建该按钮组合框 |
| BS_LEFTTEXT | 创建单选按钮或复选按钮时,指定按钮名称的文本出现在左边 |
| BS_OWNERDRAW | 指定一个自绘按钮 |
| BS_PUSHBUTTON | 指定一个命令按钮 |
| BS_RADIOBUTTON | 指定一个单选按钮,在右边显示标题 |
| BS_3STATE | 创建三态按钮 |
创建复选框按钮与创建命令按钮相同,只是在使用CreateWindow函数创建时,需要修改dwStyle的风格值,指定为“BS_AUTOCHECKBOX”风格即可,代码如下所示。
g_hButtonWnd11 = CreateWindow("BUTTON", "Check Box1",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
50, 80, 100, 20, hWnd, NULL, g_hIns, NULL);
创建多选框按钮与创建命令按钮相同,只是在使用CreateWindow函数创建时,需要修改dwStyle的风格值,指定为“BS_AUTOCHECKBOX”风格即可,代码如下所示。
g_hButtonWnd11 = CreateWindow("BUTTON", "Check Box1",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
50, 80, 100, 20, hWnd, NULL, g_hIns, NULL);
其它按钮创建类同。按钮有自己的消息类型,当点击了按钮时,它向窗口发送一个WM_COMMAND消息,这些通知消息包含在wParam的高位字节中,也就是说,如果响应按钮的消息,就需要捕获WM_COMMAND消息,并根据wParam的参数内容来判断消息的内容。
前面的代码只是将按钮创建出来,并不能响应任何消息。因为无法识别是哪个按钮,所以在按钮创建之前,需要给第个按钮定义一个唯一的标识,可以通过如下的宏来进行定义。
// 宏定义,分别定义按钮的ID #define ID_BUTTON_PUSH 0x01 #define ID_BUTTON_RADIO1 0x02 #define ID_BUTTON_RADIO2 0x03 #define ID_BUTTON_CHECK1 0x04 #define ID_BUTTON_CHECK2 0x05
其中0x01~0x05是十六进制的数值,当然也可以直接使用十进制数值,但这个数值必须是唯一的。此时需要修改CreateWindow函数的第九个参数hMenu,即使用与菜单响应一样的模式,以命令按钮为例,代码修改如下所示。
// 创建按钮
g_hButtonWnd = CreateWindow("BUTTON", "MyButton",
WS_CHILD | WS_VISIBLE, 50+80+10, 50, 100, 20,
hWnd, (HMENU) ID_BUTTON_PUSH, g_hIns, NULL);
最后,就可以对按钮的消息进行捕获了,代码如下所示。
// 菜单响应事件
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case ID_BUTTON_PUSH:
MessageBox(hWnd, "按钮被按下了...", "提示", MB_OK);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}//end switch
break;
【例10-2】实现了对命令、单选及多选按钮的创建,并对按钮的消息进行了捕获处理。
//**************************************************************
// NAME : Demo_10
//**************************************************************
// POWER : Copyright (c) 2012 for lixinghua.
// AUTHOR : 2012-7-26 16:51 Create by lixinghua for functions.
// VERSION : V1.0.0.1
// NOTE : 手工整理的创建窗口的代码,本程序只创建一个名称为MyWin的窗口。
//**************************************************************
//
#include <windows.h>
#include <stdio.h>
// 宏定义,分别定义按钮的ID
#define ID_BUTTON_PUSH 0x01
#define ID_BUTTON_RADIO1 0x02
#define ID_BUTTON_RADIO2 0x03
#define ID_BUTTON_CHECK1 0x04
#define ID_BUTTON_CHECK2 0x05
// 回调函数,用于系统消息的处理。
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hIns = NULL;
HWND g_hStaticWnd = NULL; // 静态文本框句柄
HWND g_hButtonWnd = NULL; // 按钮句柄
HWND g_hButtonWnd11 = NULL; // 按钮句柄
HWND g_hButtonWnd12 = NULL; // 按钮句柄
HWND g_hButtonWnd21 = NULL; // 按钮句柄
HWND g_hButtonWnd22 = NULL; // 按钮句柄
//-----------------------------------------------------------------------------
// FUNC : 入口函数
//-----------------------------------------------------------------------------
// IN : hInstance,进程的实例句柄;
// hPrevInstance,前一个进程实例句柄,默认为NULL即可;
// lpCmdLine,命令行参数;
// nCmdShow,当前窗口显示状态。
// OUT : void
// RETURN : 返回为整型,代表窗口的状态,其中APIENTRY描述了
// 压栈的顺序。
// AUTHOR : 2012-2-6 11:18 Create by lixinghua for functions.
// NOTE : 此函数为Win32入口函数。
//-----------------------------------------------------------------------------
//
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// 定义所用到的参数
//
char szWindowClass[] = { "WinClsName" };
// 窗口类的名称
HWND hWnd = NULL; // 用于存放窗口句柄
char szTitle[] = { "MyWin" }; // 窗口标题名称
MSG msg; // 存放消息的结构体,
// 由系统提供
// 保存进程实例句柄
g_hIns = hInstance;
// 1. 设计一个窗口类
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = NULL;
// 2. 注册窗口
RegisterClassEx(&wcex);
// 3. 创建窗口
HMENU hMenu = NULL;
hWnd = CreateWindow(szWindowClass, szTitle,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
0, CW_USEDEFAULT, 0, NULL, hMenu, hInstance, NULL);
// 判断创建是否成功
if (!hWnd)
{
return FALSE;
}//end if
// 4. 显示并更新窗口
ShowWindow(hWnd, nCmdShow); // 请注意 nCmdShow 参数
UpdateWindow(hWnd);
// 5. 进入消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}//end while
return 0;
}
//-----------------------------------------------------------------------------
// FUNC : 回调函数
//-----------------------------------------------------------------------------
// IN : hWnd,窗口句柄;
// message,要处理的消息ID,以此来区分消息;
// wParam,消息参数,根据消息的不同内容也有所不同;
// lParam,消息参数,根据消息的不同内容也有所不同。
// OUT : void
// RETURN : void
// AUTHOR : 2012-2-6 11:36 Create by lixinghua for functions.
// NOTE : 此函数用于系统消息的处理。
//-----------------------------------------------------------------------------
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps; // 结构体包含了用于绘
// 制窗口客户区的信息
HDC hdc; // 设备环境句柄
int wmId, wmEvent;
char szContext[512] = { 0 };
// 消息处理
//
switch (message)
{
// 创建窗口时响应的事件
case WM_CREATE:
// 创建静态文本控件
g_hStaticWnd = CreateWindow("STATIC", "MyStatic",
WS_CHILD | WS_VISIBLE, 50, 50, 80, 20, hWnd,
NULL, g_hIns, NULL);
// 创建按钮
g_hButtonWnd = CreateWindow("BUTTON", "MyButton",
WS_CHILD | WS_VISIBLE, 50+80+10, 50, 100, 20,
hWnd, (HMENU)ID_BUTTON_PUSH, g_hIns, NULL);
// 创建多选按钮
g_hButtonWnd11 = CreateWindow("BUTTON", "Check Box1",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
50, 80, 100, 20, hWnd, (HMENU)ID_BUTTON_RADIO1,g_hIns, NULL);
g_hButtonWnd12 = CreateWindow("BUTTON", "Check Box2",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
160, 80, 100, 20, hWnd, (HMENU)ID_BUTTON_RADIO2,g_hIns, NULL);
// 创建单选按钮
g_hButtonWnd21 = CreateWindow("BUTTON", "Radio 1",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
50, 120, 100, 20, hWnd, (HMENU)ID_BUTTON_CHECK1,g_hIns, NULL);
g_hButtonWnd22 = CreateWindow("BUTTON", "Radio 2",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
160, 120, 100, 20, hWnd, (HMENU)ID_BUTTON_CHECK2,g_hIns, NULL);
break;
// 菜单响应事件
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case ID_BUTTON_PUSH:
// 判断Check Box 1是否被按下
if(IsDlgButtonChecked(hWnd, ID_BUTTON_RADIO1))
{
strcat(szContext, "Check Box1 被按下。\r\n");
}//end if
// 判断Check Box 2是否被按下
if(IsDlgButtonChecked(hWnd, ID_BUTTON_RADIO2))
{
strcat(szContext, "Check Box2 被按下。\r\n");
}//end if
// 判断Radio 1与Radio 2哪个被按下
if(IsDlgButtonChecked(hWnd, ID_BUTTON_CHECK1))
{
strcat(szContext, "Radio 1 被按下。\r\n");
}
else if(IsDlgButtonChecked(hWnd, ID_BUTTON_CHECK2))
{
strcat(szContext, "Radio 2 被按下。\r\n");
}//end if
// 显示提示信息
MessageBox(hWnd, szContext, "提示", MB_OK);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}//end switch
break;
// 图形绘制事件
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
// 窗口销毁消息,关闭窗口时响应。
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
// 调用系统默认消息处理,即交给系统处理。
return DefWindowProc(hWnd, message, wParam, lParam);
}//end switch
return 0;
}
程序执行结果如图10.2所示。
图10.2 程序执行结果
程序中IsDlgButtonChecked函数的功能是查看单选按钮或多选按钮是否被选中,函数的返回值可能是BST_CHECKED(选中状态)、BST_INDETERMINATE(多选按钮灰化状态)或BST_UNCHECKED(未选中状态)。当然也可以像程序那样,通过值的真假来判断。如果想设计单选或多选按钮的状态,可以使用CheckDlgButton函数,通过参数来对按钮进行设置,设置的值同样是BST_CHECKED(选中状态)、BST_INDETERMINATE(多选按钮灰化状态)或BST_UNCHECKED(未选中状态)三种。
按钮控件的内容同样可以使用SetWindowText函数来设置显示的内容,使用GetWindowText函数来获得显示的内容(按钮上的文本内容)。如果对于按钮没有做其它控制性操作,按钮的句柄可以省略。