调用CreateWindow()
/ CreateWindowEx()
函数创建窗口的时候,将窗口样式指定为WS_CHILD
或WS_CHILDWINDOW
就可以创建一个子窗口。子窗口的位置可以在父窗口客户区的任何地方,这样的子窗口需要程序注册窗口类并提供窗口过程。程序也可以通过系统预定义的窗口类和窗口过程来创建标准子窗口控件,程序中常见的标准子窗口挫件有按钮、单选按钮、复选按钮、编辑框、组合框、列表框、滚动条控件等,像资源管理器窗口就包含多个子窗口控件,例如工具栏、树视图控件、滚动条控件等。标准子窗口控件也称为通用控件(Common Control) 。
程序可以把窗口类名指定为系统预定义的相关子窗口控件类名
来调用CreateWindow()
/ CreateWindowEx()
函数创建一个子窗口控件(对应形参的lpClassName
),子窗口控件和父窗口之间可以互相发送消息来进行通信。子窗口控件在对话框程序中用得更普遍,不需要调用CreateWindow()
/ CreateWindowEx()
函数,直接在资源脚本文件中定义子窗口控件即可,也可以通过资源编辑器从工具箱中拖曳子窗口控件到对话框程序界面的合适位置。
系统预定义的窗口类名字符串含义
另外,有一些类名是系统内部使用的,例如ComboLBox (多一个L)
表示组合框内的列表框的类名,#32770
表示对话框类名等。
按钮(Button)类有许多样式属性,基于Button类指定不同的样式可以创建普通按钮、单选按钮、复选按钮和分组框等。Button类可以指定的按钮样式如表所示,BS_前缀表示Button Style.
宏 | 含义 |
---|---|
BS_PUSHBUTTON | 普通按钮 |
BS_DEFPUSHBUTTON | 默认按钮,和普通按钮一样,但是有一个较深的轮廓。如果是在对话框程序中,当其他按钮没有键盘焦点时,用户可以通过按下Enter键选择该按钮 |
BS_RADIOBUTTON | 单选按钮,可以选中、取消选中 |
BS_AUTOCHECKBOX | 自动单选按钮 |
BS_RADIOBUTTON | 自动复选框 |
BS_AUTORADIOBUTTON | 单选按钮,可以选中、取消选中 |
BS_CHECKBOX | 复选框,可以选中,取消选中。 |
BS_ATUOCHECKBOX | 自动复选框 |
BS_ATUO3TATE | 自动三态复选框 |
BS_LEFTTEXT或BS_RIGHTBUTTON | 对于单选按钮﹑复选框或三态复选框,文本默认显示在按钮右侧,该样式表示显示在按钮左侧 |
BS_TEXT | 按钮矩形内显示文本 |
BS_LEFT | 左对齐按钮矩形内的文本 |
BS_RIGHT | 右对齐按钮矩形内的文本 |
BS_CENTTER | 文本在按钮矩形内水平居中 |
BS_TOP | 文本在按钮矩形的顶部 |
BS_BOTTOM | 文本在按钮矩形的底部 |
BS_VCENTER | 文本在按钮矩形内垂直居中 |
BS_FLAT | 按钮默认具有三维样式,该样式表示按钮是二维样式 |
BS_PUSHLIKE | 使单选按钮、复选框或三态复选框看起来像按钮—样 |
BS_OWNERDRAW | 自绘按钮,当按钮需要重绘时父窗口会收到WM_DRAWITEM消息,不能将该样式与任何其他按钮样式—起使用 |
BS_ICON | 图标按钮 |
BS_BITMAP | 位图按钮 |
BS_GROUPBOX | 分组框,用于对其他控件进行分组,由一个矩形和显示在矩形左上角的文本组成 |
BS_NOTIFY | 系统可以发送包含BN_KTLLFOCUS 和BS_SETFOCUS 通知码的WM_COMMAND消息到其父窗口 |
BS_SPLITBUTTON | 拆分按钮。拆分按钮分为两部分,左侧是主要部分,类似于普通或默认按纽﹔右刻有一个向下的小箭头,单击箭头时可以弹出一个菜单。拆分按扭是通用控件版本6中引A的一种出钮,如图所示: |
BS_DEFSPLITBUTTON | 默认拆分按钮,有一个较深的轮廓。如果是在对话框程序中,当其他按钮没有键盘焦点时,用户可以通过按下Eat er键选择该按钮 |
BS_COMMANDLTNK | 命令链接按钮,左侧有一个篮色箭头指向按钮文本(Windows 7系统中为绿色箭头〉。命令链接按钮是通用控件版本6中引入的一种按钮 |
下面介绍自动单选按钮、自动复选框和自动三态复选框。以三态复选框与自动三态复选框为例,用户单击三态复选框以后不会自动选中或变灭,程序需要响应单击事件设置选中或变灰状态﹔而如果是自动三态复选框,则单击一次就会自动选中,再单击一次则复选框显示为灰色,第三次单击则会取消选中,如此循环,程序在需要的时候只需要获取其状态即可。
普通按钮、默认按钮、单选按钮和复选框都可以同时指定BS_ICON或BS BITMAP样式,例如BS_PUSHBUTTON|BS_BITMAP
,或BS_AUTORADIOBUTTON| BS_BITMAP
,表示在普通按钮上显示一副位图,或单选按钮旁边显示一副位图。BS_ICON
或BS_BITMAP
样式也可以单独使用,表示在普通按钮上显示一个图标或一副位图。指定BS_ICON或BS_BITMAP样式以后,需要发送BM_SETIMAGE消息为其设置图标或位图,后面再详细解释这个消息。
BS_前缀的样式是按钮专用样式。除了这些按钮专用样式,因为子窗口控件也是一个窗口,所以大部分用于普通窗口的API函数和窗口样式适用于子窗口控件。例如下表的窗口样式可以用于按钮。
宏 | 含义 |
---|---|
WS_CHILD 或WS_CHILDWINDOW | 窗口是子窗口 |
WS_VISIBLE | WS_VISABLE 窗口最初可见,可以通过调用ShowWindow() 或SetWindowPos() 函数显示和隐藏窗口 |
WS_GROUP | WS_GROUP 该窗口是一组控件的第一个控件,该组由第一个具有WS_GROUP样式的控件和在其后定义的所有控件组成,直到下一个具有WS_GROUP 样式的控件(不包括该控件)出现。如果是在对话框程序中,用户可以使用方向键将键盘焦点从组中的一个控件移动到下一个控件。另外,每个组中的第一个控件通常具有WS_TABSTOP 样式,如果是在对话框程序中,按下Tab键可以将键盘焦点移动到下一个具有WS_TABSTOP 样式的按件。 |
WS_TABSTOP | 该窗口是一个控件,当用户按下Tab键时,该控件可以接收键盘焦点,如果是在对话框程序中,按下Tab键可以将键盘焦点移动到下一个具有WS_TABSTOP 样式的控件上 |
WS_BORDER | 窗口有一个细线边框 |
WS_DLGFRAME | 窗口具有对话框样式的边框 |
WS_SIZEBOX 或 WS_THICKFRAME | 窗口具有大小调整边框 |
WS_DISABLED | 窗口最初被禁用,禁用的窗口无法接收用户的输入,要想启用可以调用EnableWindow() 函数 |
其中,WS_CHILD
和WS_VISIBLE
是必须指定的,WS_CHILD
表示该窗口是一个子窗口。如果不指定WS_VISIBLE
样式,则子窗口控件不会显示。
另外,一些扩展窗口样式也可以用于子窗口控件,例如WS_EX_ACCEPTFILES
表示该子窗口控件可以接受拖放文件。
按钮可以向其父窗口发送消息,父窗口也可以向按钮发送消息。父窗口可以通过调用SendMessage()
或SendDlgltemMessage()
函数发送消息到子窗口控件∶
LRESULT SendMessage(HWND hWnd, UINT Msg,WPARAM wParam,LPARAM lParam);
LRESULT SendDIgItemMessage(HWND hDIg, int nIDDIgltem, UINT Msg, WPARAM wParam,LPARAM lParam);
SendDlgltemMessage()
函数的hDlg
指的是Dialog对话框,该函数通常用于在对话框程序中向子窗口控件发送消息,但是也可以在普通重叠窗口中向子窗口控件发送消息。hDlg
参数指定父窗口句柄,
nIDDIgltem
参数指定子窗口控件ID,每个子窗口控件都有一个ID。调用CreateWindow/CreateWindowEx
函数创建子窗口控件的时候,第10个参数hMenu
不再指定为菜单句柄,而是指定为子窗口控件ID。
对于BS_ICON
或BS_BITMAP
样式的按钮,BM_SETIMAGE
消息用于为按钮设置图标或位图。
wParam
参数指定图像类型,可以是IMAGE_ICON(图标)或IMAGE_BITMAP(位图),lParam
参数可以指定为图像的句柄(HICON或HBITMAP),返回值
是先前与按钮关联的图像的句柄(如果有的话),否则返回值是NULL ;BM_GETIMAGE
消息用于获取与按钮关联的图标或位图的句柄.
wParam
参数指定图像类型,可以是IMAGE_ICON(图标)或IMAGE_BITMAP(位图)lParam
参数没有用到,指定为0即可。返回值
是与按钮关联的图像的句柄(如果有的话),否则返回值是NULL。BM_SETSTYLE
消息用于设置按钮的样式.
wParam
参数可以指定为按钮新样式的组合lParam
参数可以指定为TRUE(重绘按钮)或FALSE(不重绘按钮)。当然,通过调用SetWindowLongPtr()
函数也可以达到同样的目的。BM_SETCHECK
消息用于设置单选按钮、复选框或三态复选框的选中状态.
wParam
参数可以指定为BST_CHECKED (选中)、BST_UNCHECKED (取消选中)或BST_INDETERMINATE(灰色,表示不确定状态,用于三态复选框)lParam
参数没有用到,指定为0即可。BM_GETCHECK
消息用于获取单选按钮、复选框或三态复选框的选中状态.
wParam
和lParam
参数没有用到,都指定为0即可返回值
可以是BST_CHECKED (已选中)、BST_UNCHECKED (未选中)或BST_INDETERMINATE(灰色,表示不确定状态,用于三态复选框)。BM_SETSTATE
消息用于设置普通按钮是否按下的状态.
wParam
参数可以指定为TRUE(突出显示,按下状态)或FALSE(取消突出显示,非按下状态)lParam
参数没有用到,指定为0即可。BM_GETSTATE
消息用于获取普通按钮、单选按钮、复选框或三态复选框的当前状态(选中状态,是否按下和是否具有键盘焦点等)
wParam
和lParam
参数没有用到,都指定为0即可.BM_CLICK
消息可以模拟用户单击按钮
lParam
参数都没有用到。该消息会导致系统向按钮的父窗口发送包含BN_CLICKED通知码的WM_COMMAND消息。调用CheckDlgButton()
或CheckRadioButton()
函数等同于发送BM_SETCHECK消息
调用IsDlgButtonChecked()
函数等同于发送BM_GETCHECK消息
BOOL CheckDlgButton(
_In_ HWND hDIg,//父窗口句柄
_In_ int nIDButton, //子窗口控件ID
_In_ UINTuCheck //设置选中状态,BST_CHECKED BST_UNCHECKED或BST_INDETERMINATE
);
BOOL CheckRadioButton(
_In_ HWND hDlg,//父窗口句柄
_In_ int nlDFirstButton,//组中第一个单选按钮的ID
_In_ int nlDLastButton,//组中最后一个单选按钮的ID
_ln_ int nlDCheckButton //要设置选中的单选按钮的ID
);
UINT IsDlgButtonChecked(
_In_ HWND hDlg,//父窗口句柄
_In_ int nlDButton //子窗口控件ID,
);
//函数返回值可以是BST_CHECKED BST_UNCHECKED或BST_INDETERMINATE
一组复选按钮中通常可以同时选中多个,而一组单选按钮中通常只能选中一个。CheckDlgButton()
函数通常用于设置复选框的选中状态。
CheckDlgButton()
函数也可以用于设置单选按钮,但是如果在一组单选按钮中选中一个,还需要多次调用CheckDlgButton()
取消选中其他的,所以设置单选按钮的状态通常使用CheckRadioButton()
函数,指定一组单选按钮的第一个和最后一个以及需要选中哪一个,函数会自动完成任务。
建议使用自动单选按钮,同组的单选按钮会随着用户选中一个而自动取消选中其他单选按钮。在程序中只需要在初始化的时候设置选中哪一个,并在需要查用户选择了哪一个的时候调用lsDlgButtonChecked()
函数检查每一个单选按钮项的选中状态即可。
同样,复选按钮也不会因为用户的单击而自动变为选中或取消选中等,因此建议使用自动复选按钮,在初始化的时候设置选中哪些,并在需要的时候调用lsDlgButtonChecked()
函数检查每一个的状态即可。
当用户单击按钮时,它会接收键盘焦点,系统会向按钮的父窗口发送包含BN_CLICKED
通知码的WM_COMMAND
消息。不过对于自动单选按钮、自动复选框或自动三态复选框通常不需要处理该消息,因为这些按钮可以自动设置其状态。如果是普通按钮,则可能需要处理该消息。
下表再次列出WM_COMMAND
消息的wParam
和IParam
参数的含义。
HIWORD (wParam) | LOWORD (wParam) | HWND(lParam) |
---|---|---|
菜单命今ID 比如说,ID_MEUN | 菜单项ID,比如说,记事本程序的打开菜单项IDIDM_FILE_OPEN ,保存菜单项IDM_FILE_SAVE | 0 |
加速键(快捷键) | 菜单项ID,同上 | 0 |
子窗口控件通知码,比如说BN_CLICKED 按钮比点击了。 | 控件ID,比如说按钮控件的IDID_BUTTON | 控件句柄 |
通知码,可以类比QT中的发出的信号。
// 为按钮绑定事件 connect(信号的发送者,发送的信号,信号的接受者,处理的函数(槽函数))
connect(btn, &QPushButton::clicked, this, &QWidget::close);
BN_SETFOCUS
: 按钮获得了键盘焦点
BN_KILLFOCUS
:按钮失去了键盘焦点
BN_DBLCLK
或BN_DOUBLECLICKED
:双击按钮
获得键盘焦点的按钮周围会显示一圈虚线,此时按下空格键就相当于单击了按钮。只有具有BS_NOTIFY
样式的按钮会发送BN_SETFOCUS
BN_KILLFOCUS
和BN_DBLCLK
通知码,但是无论如何设置按钮样式,单击按钮都会发送BN_CLICKED
通知码。
BS_GROUPBOX
样式表示分组框,用于对其他控件进行分组,由一个矩形和显示在矩形左上角的文本组成。分组框不会获得键盘焦点,既不处理鼠标或键盘输入,也不会导致系统发送WM_COMMAND
消息到父窗口。
对于自绘按钮、组合框和列表框等,程序只需要在必要的时候负责绘制它们的外观即可,系统会正常处理用户和这些控件的交互,例如用户单击控件,系统会向父窗口发送WM_COMMAND
消息。在介绍自绘菜单的时候说过,WM_DRAWITEM
消息既用于菜单项,也用于其他些子窗口控件的自绘,当菜单项或子窗口控件需要自绘的时候,窗口过程会收到WM_DRAWITEM消息。
如果WM_DRAWITEM消息是由子窗口控件发送的,则wParam
参数是子窗口控件的ID
如果是由菜单项发送的,则wParam
参数为0。lParam
参数是一个指向DRAWITEMSTRUCT
结构的指
针.
typedef struct tagDRAWITEMSTRUCT
{
UINT ctlType;//控件类型,如果是ODT_MENU,表示菜单项
UINT CtlID;//该字段不用于菜单项
UINT itemID;//菜单项ID
UINT itemAction; //所需的绘制操作
UINT itemState;//新的状态
HWND hwndItem;//菜单句柄
HDC hDC;//设备环境句柄
RECT rcItem;//绘制区域
ULONG_PTR itemData;//程序自定义数据,最初由MENUITEMINFO结构的dwltemData指定的
}DRAWITEMSTRUCT,NEAR *PDRAWITEMSTRUCT,FAR *LPDRAWITEMSTRUCT;
接下来实现一个例子,Buttons程序在窗口客户区中使用系统预定义的Button类调用CreateWindowEx()
函数分别创建了普通按钮、图标按钮、位图按钮、自绘按钮、一组自动单选按钮、一组自动复选按钮、一组自动三态复选按钮、默认按钮。
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 Buttons.rc 使用
//
#define IDB_KONGLONG 101
#define IDI_SMILE 102
#define IDC_PUSHBUTTON 1000
#define IDC_ICONBUTTON 1001
#define IDC_BITMAPBUTTON 1002
#define IDC_OWNERDRAWBUTTON 1003
#define IDC_GROUPBOX1 1004
#define IDC_AUTORADIOBUTTON1 1005
#define IDC_AUTORADIOBUTTON2 1006
#define IDC_AUTORADIOBUTTON3 1007
#define IDC_GROUPBOX2 1008
#define IDC_AUTOCHECKBOX1 1009
#define IDC_AUTOCHECKBOX2 1010
#define IDC_AUTOCHECKBOX3 1011
#define IDC_GROUPBOX3 1012
#define IDC_AUTO3STATE1 1013
#define IDC_AUTO3STATE2 1014
#define IDC_AUTO3STATE3 1015
#define IDC_DEFPUSHBUTTON 1016
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1017
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>
#include "resource.h"
// 函数声明
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 按下默认按钮
VOID OnDefPushButton(HWND hwnd);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wndclass;
TCHAR szAppName[] = TEXT("Buttons"); // 程序标题、窗口类名
HWND hwnd;
MSG msg;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
wndclass.hIconSm = NULL;
RegisterClassEx(&wndclass);
hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 600, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// 全局变量
struct
{
int m_nStyle;
PTSTR m_pText;
}Buttons[] = {
BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP, TEXT("普通按钮"), // CtrlID 1000
BS_ICON | BS_NOTIFY | WS_TABSTOP, TEXT("图标按钮"),
BS_BITMAP | BS_NOTIFY | WS_TABSTOP, TEXT("位图按钮"),
BS_OWNERDRAW, TEXT("自绘按钮"),
BS_GROUPBOX, TEXT("政治面貌"), // CtrlID 1004
BS_AUTORADIOBUTTON | BS_NOTIFY | WS_GROUP | WS_TABSTOP, TEXT("中共党员"),
BS_AUTORADIOBUTTON | BS_NOTIFY, TEXT("共青团员"),
BS_AUTORADIOBUTTON | BS_NOTIFY, TEXT("无党派人士"),
BS_GROUPBOX, TEXT("个人爱好"), // CtrlID 1008
BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP, TEXT("看书"),
BS_AUTOCHECKBOX | BS_NOTIFY, TEXT("唱歌"),
BS_AUTOCHECKBOX | BS_NOTIFY, TEXT("听音乐"),
BS_GROUPBOX, TEXT("荣誉称号"), // CtrlID 1012
BS_AUTO3STATE | BS_NOTIFY | WS_GROUP | WS_TABSTOP, TEXT("团队核心"),
BS_AUTO3STATE | BS_NOTIFY, TEXT("技术能手"),
BS_AUTO3STATE | BS_NOTIFY, TEXT("先进个人"),
BS_DEFPUSHBUTTON | BS_NOTIFY | WS_TABSTOP, TEXT("默认按钮"), // CtrlID 1016
};
#define NUM (sizeof(Buttons) / sizeof(Buttons[0]))
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndButton[NUM]; // 子窗口控件句柄数组
int arrPos[NUM] = {10, 40, 70, 100, // 每个子窗口控件的起始Y坐标
130, 150, 180, 210,
250, 270, 300, 330,
370, 390, 420, 450,
490 };
LPDRAWITEMSTRUCT lpDIS;
if (WM_CREATE == uMsg)
{
for (int i = 0; i < NUM; i++)
{
// 创建17个子窗口控件
hwndButton[i] = ::CreateWindowEx(
0,
TEXT("Button"),
Buttons[i].m_pText,
WS_CHILD | WS_VISIBLE | Buttons[i].m_nStyle,
20, arrPos[i],
150, 25,
hwnd,
(HMENU)(1000 + i),
((LPCREATESTRUCT)lParam)->hInstance, NULL);
}
// 移动3个分组框的位置
::MoveWindow(hwndButton[4], 10, arrPos[4], 170, 115, TRUE);
::MoveWindow(hwndButton[8], 10, arrPos[8], 170, 115, TRUE);
::MoveWindow(hwndButton[12], 10, arrPos[12], 170, 115, TRUE);
// 为图标按钮、位图按钮设置图标、位图
HANDLE hImage = ::LoadImage(((LPCREATESTRUCT)lParam)->hInstance, MAKEINTRESOURCE(IDI_SMILE), IMAGE_ICON, 20, 20, LR_DEFAULTCOLOR); //根据resourceID 查图片句柄
::SendDlgItemMessage(hwnd, IDC_ICONBUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hImage); //给按钮设置图标
HBITMAP hBitMap = ::LoadBitmap(((LPCREATESTRUCT)lParam)->hInstance, MAKEINTRESOURCE(IDB_KONGLONG));// 根据resourceID 查位图句柄
::SendDlgItemMessage(hwnd, IDC_BITMAPBUTTON, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitMap); //给按钮设置位图
// 设置默认按钮的文本
::SetDlgItemText(hwnd, IDC_DEFPUSHBUTTON, TEXT("获取单选复选状态"));
// 单选按钮组、复选按钮组、三态复选按钮组,默认情况下分别选中一项
::CheckRadioButton(hwnd, IDC_AUTORADIOBUTTON1, IDC_AUTORADIOBUTTON3, IDC_AUTORADIOBUTTON2);
::CheckDlgButton(hwnd, IDC_AUTOCHECKBOX3, BST_CHECKED);
::CheckDlgButton(hwnd, IDC_AUTO3STATE2, BST_INDETERMINATE);
return 0;
}
else if (WM_COMMAND == uMsg)
{
if (HIWORD(wParam) == BN_CLICKED)
{
// 子窗口控件ID常量定义请参见resource.h,可以根据需要在此处理每个控件的点击事件
if (LOWORD(wParam) == IDC_PUSHBUTTON)
{
}
else if (LOWORD(wParam) == IDC_ICONBUTTON)
{
}
else if (LOWORD(wParam) == IDC_BITMAPBUTTON)
{
}
else if (LOWORD(wParam) == IDC_OWNERDRAWBUTTON)
{
}
else if (LOWORD(wParam) == IDC_AUTORADIOBUTTON1)
{
}
else if (LOWORD(wParam) == IDC_AUTORADIOBUTTON2)
{
}
else if (LOWORD(wParam) == IDC_AUTORADIOBUTTON3)
{
}
else if (LOWORD(wParam) == IDC_AUTOCHECKBOX1)
{
}
else if (LOWORD(wParam) == IDC_AUTOCHECKBOX2)
{
}
else if (LOWORD(wParam) == IDC_AUTOCHECKBOX3)
{
}
else if (LOWORD(wParam) == IDC_AUTO3STATE1)
{
}
else if (LOWORD(wParam) == IDC_AUTO3STATE2)
{
}
else if (LOWORD(wParam) == IDC_AUTO3STATE3)
{
}
else if (LOWORD(wParam) == IDC_DEFPUSHBUTTON)
{
OnDefPushButton(hwnd);
}
}
return 0;
}
else if (WM_DRAWITEM == uMsg)
{
//按钮重绘
lpDIS = (LPDRAWITEMSTRUCT)lParam;
// 先把按钮矩形填充为和窗口背景一致的白色,然后画一个黑色圆角矩形
::SelectObject(lpDIS->hDC, GetStockObject(NULL_PEN));
::SelectObject(lpDIS->hDC, GetStockObject(WHITE_BRUSH));
::Rectangle(lpDIS->hDC, 0, 0, lpDIS->rcItem.right + 1, lpDIS->rcItem.bottom + 1);
::SelectObject(lpDIS->hDC, GetStockObject(BLACK_BRUSH));
::RoundRect(lpDIS->hDC, 0, 0, lpDIS->rcItem.right + 1, lpDIS->rcItem.bottom + 1, 20, 20);
// 当用户点击按钮的时候,绘制COLOR_HIGHLIGHT颜色的圆角矩形
if (lpDIS->itemState & ODS_SELECTED)
{
SelectObject(lpDIS->hDC, GetSysColorBrush(COLOR_HIGHLIGHT));
RoundRect(lpDIS->hDC,0, 0, lpDIS->rcItem.right + 1, lpDIS->rcItem.bottom + 1,20,20);
}
if (lpDIS->itemState & ODS_FOCUS)
{
::InflateRect(&lpDIS->rcItem, -2, -2);
::DrawFocusRect(lpDIS->hDC, &lpDIS->rcItem);
}
// 自绘按钮的文本,透明背景的白色文字
::SetBkMode(lpDIS->hDC, TRANSPARENT);
::SetTextColor(lpDIS->hDC, RGB(255, 255, 255));
::DrawText(lpDIS->hDC, TEXT("自绘按钮"), _tcslen(TEXT("自绘按钮")), &lpDIS->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
// 恢复设备环境
::SelectObject(lpDIS->hDC, GetStockObject(BLACK_PEN));
::SelectObject(lpDIS->hDC, GetStockObject(WHITE_BRUSH));
}
else if (WM_DESTROY == uMsg)
{
PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
VOID OnDefPushButton(HWND hwnd)
{
TCHAR szBuf[128] = { 0 };
//查自动单选按钮 哪一项被选中了
if (::IsDlgButtonChecked(hwnd, IDC_AUTORADIOBUTTON1) & BST_CHECKED)
{
::StringCchCopy(szBuf, _countof(szBuf), TEXT("政治面貌:中共党员\n"));
}
if (::IsDlgButtonChecked(hwnd, IDC_AUTORADIOBUTTON2) & BST_CHECKED)
{
::StringCchCopy(szBuf, _countof(szBuf), TEXT("政治面貌:共青团员\n"));
}
if (::IsDlgButtonChecked(hwnd, IDC_AUTORADIOBUTTON3) & BST_CHECKED)
{
::StringCchCopy(szBuf, _countof(szBuf), TEXT("政治面貌:无党派人士\n"));
}
//查自动复选按钮中 哪一个自动复选按钮项被选中了
::StringCchCat(szBuf, _countof(szBuf), TEXT("个人爱好:"));
if (::IsDlgButtonChecked(hwnd, IDC_AUTOCHECKBOX1) & BST_CHECKED)
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("看书 "));
}
if (::IsDlgButtonChecked(hwnd, IDC_AUTOCHECKBOX2) & BST_CHECKED)
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("唱歌 "));
}
if (::IsDlgButtonChecked(hwnd, IDC_AUTOCHECKBOX3) & BST_CHECKED)
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("听音乐"));
}
::StringCchCat(szBuf, _countof(szBuf), TEXT("\n"));
::StringCchCat(szBuf, _countof(szBuf), TEXT("荣誉称号:"));
//查 自动三态复选按钮 哪一个自动三态复选按钮被选中了
if (::IsDlgButtonChecked(hwnd, IDC_AUTO3STATE1) & BST_CHECKED)
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("团队核心 "));
}
if (::IsDlgButtonChecked(hwnd, IDC_AUTO3STATE2) & BST_CHECKED)
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("技术能手 "));
}
if (::IsDlgButtonChecked(hwnd, IDC_AUTO3STATE3) & BST_CHECKED)
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("先进个人"));
}
::StringCchCat(szBuf, _countof(szBuf), TEXT("\n"));
::MessageBox(hwnd, szBuf, TEXT("个人简介汇总"), MB_OK);
}
在MFC中这些类型的按钮都用一个CButton
类来表示。同样的WIN32的程序我们也可以用MFC来实现。要实现按钮自绘的话,MFC中通过继承CButton来做。
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 HelloMFC.rc 使用
//
#define IDM_ABOUTBOX 0x0010
#define IDS_ABOUTBOX 101
#define IDB_KONGLONG 150
#define IDD_HELLOMFC_DIALOG 102
#define IDI_ICON1 160
#define IDI_SMILE 174
#define IDR_MAINFRAME 128
#define IDC_PUSHBUTTON 1000
#define IDC_ICONBUTTON 1001
#define IDC_BITMAPBUTTON 1002
#define IDC_OWNERDRAWBUTTON 1003
#define IDC_GROUPBOX1 1004
#define IDC_AUTORADIOBUTTON1 1005
#define IDC_AUTORADIOBUTTON2 1006
#define IDC_AUTORADIOBUTTON3 1007
#define IDC_GROUPBOX2 1008
#define IDC_AUTOCHECKBOX1 1009
#define IDC_AUTOCHECKBOX2 1010
#define IDC_AUTOCHECKBOX3 1011
#define IDC_GROUPBOX3 1012
#define IDC_AUTO3STATE1 1013
#define IDC_AUTO3STATE2 1014
#define IDC_AUTO3STATE3 1015
#define IDC_DEFPUSHBUTTON 1016
#define IDC_BUTTON1 1017
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 107
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1032
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
#pragma once
#include <winnt.h>
#include <WinUser.h>
#include<string>
class COwnderButton;
class CHelloMFCDlg;
class COwnderButton:public CButton
{
DECLARE_DYNAMIC(COwnderButton)
public:
COwnderButton();
~COwnderButton();
protected:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
virtual void PreSubclassWindow();
};
class CHelloMFCDlg : public CDialogEx
{
public:
CHelloMFCDlg(CWnd* pParent = nullptr);
~CHelloMFCDlg();
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_HELLOMFC_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual void PreSubclassWindow();
protected:
HICON m_hIcon;
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
private:
virtual void PostNcDestroy();
public:
CButton m_pushButton;
CButton m_iconButton;
CButton m_bitmapButton;
COwnderButton m_ownedrawButton;
CStatic m_groupbox1;
CButton m_autoRadioButton1;
CButton m_autoRadioButton2;
CButton m_autoRadioButton3;
CStatic m_groupbox2;
CButton m_autoCheckBox1;
CButton m_autoCheckBox2;
CButton m_autoCheckBox3;
CStatic m_groupbox3;
CButton m_auto3State1;
CButton m_auto3State2;
CButton m_auto3State3;
CButton m_defpushButton;
afx_msg void OnBnClickedDefpushbutton();
};
// HelloMFCDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "HelloMFC.h"
#include "HelloMFCDlg.h"
#include "afxdialogex.h"
#include <strsafe.h>
#include <afxcmn.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
BEGIN_MESSAGE_MAP(CHelloMFCDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_DEFPUSHBUTTON, &CHelloMFCDlg::OnBnClickedDefpushbutton)
END_MESSAGE_MAP()
CHelloMFCDlg::CHelloMFCDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_HELLOMFC_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CHelloMFCDlg::~CHelloMFCDlg()
{
//delete[] button;
}
void CHelloMFCDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PUSHBUTTON, m_pushButton);
DDX_Control(pDX, IDC_ICONBUTTON,m_iconButton);
DDX_Control(pDX, IDC_BITMAPBUTTON,m_bitmapButton);
DDX_Control(pDX, IDC_OWNERDRAWBUTTON, m_ownedrawButton);
DDX_Control(pDX, IDC_AUTORADIOBUTTON1,m_autoRadioButton1);
DDX_Control(pDX, IDC_AUTORADIOBUTTON2, m_autoRadioButton2);
DDX_Control(pDX, IDC_AUTORADIOBUTTON3, m_autoRadioButton3);
DDX_Control(pDX, IDC_AUTOCHECKBOX1, m_autoCheckBox1);
DDX_Control(pDX, IDC_AUTOCHECKBOX2, m_autoCheckBox2);
DDX_Control(pDX, IDC_AUTOCHECKBOX3, m_autoCheckBox3);
DDX_Control(pDX, IDC_AUTO3STATE1,m_auto3State1);
DDX_Control(pDX, IDC_AUTO3STATE2, m_auto3State2);
DDX_Control(pDX, IDC_AUTO3STATE3, m_auto3State3);
DDX_Control(pDX, IDC_DEFPUSHBUTTON,m_defpushButton);
DDX_Control(pDX, IDC_GROUPBOX1, m_groupbox1);
DDX_Control(pDX, IDC_GROUPBOX2, m_groupbox2);
DDX_Control(pDX, IDC_GROUPBOX3, m_groupbox3);
}
BOOL CHelloMFCDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
//设置17个子窗口控件样式
m_pushButton.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP);
m_pushButton.SetWindowText(_T("普通按钮"));
m_iconButton.SetButtonStyle(WS_CHILD | WS_VISIBLE| BS_ICON | BS_NOTIFY | WS_TABSTOP);
m_iconButton.SetWindowText(_T("图标按钮"));
m_bitmapButton.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_BITMAP | BS_NOTIFY | WS_TABSTOP);
m_bitmapButton.SetWindowText(_T("位图按钮"));
m_ownedrawButton.SetButtonStyle(WS_CHILD | WS_VISIBLE|BS_OWNERDRAW);
m_ownedrawButton.SetWindowText(_T("自绘按钮"));
m_groupbox1.SetWindowText(_T("政治面貌"));
m_autoRadioButton1.SetButtonStyle(WS_CHILD | WS_VISIBLE|BS_AUTORADIOBUTTON | BS_NOTIFY | WS_GROUP | WS_TABSTOP);
m_autoRadioButton1.SetWindowText(_T("中共党员"));
m_autoRadioButton2.SetButtonStyle(WS_CHILD | WS_VISIBLE |BS_AUTORADIOBUTTON | BS_NOTIFY);
m_autoRadioButton2.SetWindowText(_T("共青团员"));
m_autoRadioButton3.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | BS_NOTIFY);
m_autoRadioButton3.SetWindowText(_T("无党派人士"));
m_groupbox2.SetWindowText(_T("个人爱好"));
m_autoCheckBox1.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP);
m_autoCheckBox1.SetWindowText(TEXT("看书"));
m_autoCheckBox2.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_NOTIFY);
m_autoCheckBox2.SetWindowText(TEXT("唱歌"));
m_autoCheckBox3.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_NOTIFY);
m_autoCheckBox3.SetWindowText(TEXT("听音乐"));
m_groupbox3.SetWindowText(TEXT("荣誉称号"));
m_auto3State1.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_AUTO3STATE | BS_NOTIFY | WS_GROUP | WS_TABSTOP);
m_auto3State1.SetWindowText(TEXT("团队核心"));
m_auto3State2.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_AUTO3STATE | BS_NOTIFY);
m_auto3State2.SetWindowText(TEXT("技术能手"));
m_auto3State3.SetButtonStyle(WS_CHILD | WS_VISIBLE | BS_AUTO3STATE | BS_NOTIFY);
m_auto3State3.SetWindowText(TEXT("先进个人"));
m_defpushButton.SetWindowText(TEXT("默认按钮"));
//设置按钮的选中状态
m_autoRadioButton1.SetCheck(BST_UNCHECKED);
m_autoRadioButton2.SetCheck(BST_CHECKED);
m_autoRadioButton3.SetCheck(BST_UNCHECKED);
m_autoCheckBox1.SetCheck(BST_UNCHECKED);
m_autoCheckBox2.SetCheck(BST_UNCHECKED);
m_autoCheckBox3.SetCheck(BST_CHECKED);
m_auto3State1.SetCheck(BST_UNCHECKED);
m_auto3State2.SetCheck(BST_INDETERMINATE);
m_auto3State3.SetCheck(BST_UNCHECKED);
return TRUE;
}
void CHelloMFCDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
CDialogEx::OnSysCommand(nID, lParam);
}
void CHelloMFCDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this);
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
HCURSOR CHelloMFCDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CHelloMFCDlg::PostNcDestroy()
{
// TODO: 在此添加专用代码和/或调用基类
delete this;
CDialogEx::PostNcDestroy();
}
IMPLEMENT_DYNAMIC(COwnderButton, CButton)
BEGIN_MESSAGE_MAP(COwnderButton, CButton)
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()
void COwnderButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
// 先把按钮矩形填充为和窗口背景一致的白色,然后画一个黑色圆角矩形
::SelectObject(lpDIS->hDC, GetStockObject(NULL_PEN));
::SelectObject(lpDIS->hDC, GetStockObject(WHITE_BRUSH));
::Rectangle(lpDIS->hDC, 0, 0, lpDIS->rcItem.right + 1, lpDIS->rcItem.bottom + 1);
::SelectObject(lpDIS->hDC, GetStockObject(BLACK_BRUSH));
::RoundRect(lpDIS->hDC, 0, 0, lpDIS->rcItem.right + 1, lpDIS->rcItem.bottom + 1, 20, 20);
// 当用户点击按钮的时候,绘制COLOR_HIGHLIGHT颜色的圆角矩形
if (lpDIS->itemState & ODS_SELECTED)
{
SelectObject(lpDIS->hDC, GetSysColorBrush(COLOR_HIGHLIGHT));
RoundRect(lpDIS->hDC, 0, 0, lpDIS->rcItem.right + 1, lpDIS->rcItem.bottom + 1, 20, 20);
}
if (lpDIS->itemState & ODS_FOCUS)
{
::InflateRect(&lpDIS->rcItem, -2, -2);
::DrawFocusRect(lpDIS->hDC, &lpDIS->rcItem);
}
// 自绘按钮的文本,透明背景的白色文字
::SetBkMode(lpDIS->hDC, TRANSPARENT);
::SetTextColor(lpDIS->hDC, RGB(255, 255, 255));
::DrawText(lpDIS->hDC, TEXT("自绘按钮"), _tcslen(TEXT("自绘按钮")), &lpDIS->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
// 恢复设备环境
::SelectObject(lpDIS->hDC, GetStockObject(BLACK_PEN));
::SelectObject(lpDIS->hDC, GetStockObject(WHITE_BRUSH));
}
void COwnderButton::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CButton::OnMouseMove(nFlags, point);
//MessageBox("鼠标移动到了按钮!");
}
void COwnderButton::PreSubclassWindow()
{
}
COwnderButton::COwnderButton()
{
}
COwnderButton::~COwnderButton()
{
}
void CHelloMFCDlg::PreSubclassWindow()
{
// TODO: 在此添加专用代码和/或调用基类
CDialogEx::PreSubclassWindow();
// 加载位图资源
}
void CHelloMFCDlg::OnBnClickedDefpushbutton()
{
// TODO: 在此添加控件通知处理程序代码
TCHAR szBuf[128] = { 0 };
if (m_autoRadioButton1.GetCheck())
{
::StringCchCopy(szBuf, _countof(szBuf), TEXT("政治面貌:中共党员\n"));
}
if (m_autoRadioButton2.GetCheck())
{
::StringCchCopy(szBuf, _countof(szBuf), TEXT("政治面貌:共青团员\n"));
}
if (m_autoRadioButton3.GetCheck())
{
::StringCchCopy(szBuf, _countof(szBuf), TEXT("政治面貌:无党派人士\n"));
}
::StringCchCat(szBuf, _countof(szBuf), TEXT("个人爱好:"));
if (m_autoCheckBox1.GetCheck())
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("看书 "));
}
if (m_autoCheckBox2.GetCheck())
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("唱歌 "));
}
if (m_autoCheckBox3.GetCheck())
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("听音乐"));
}
::StringCchCat(szBuf, _countof(szBuf), TEXT("\n"));
::StringCchCat(szBuf, _countof(szBuf), TEXT("荣誉称号:"));
if (m_auto3State1.GetCheck())
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("团队核心 "));
}
else if (m_auto3State2.GetCheck())
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("技术能手 "));
}
else if (m_auto3State3.GetCheck())
{
::StringCchCat(szBuf, _countof(szBuf), TEXT("先进个人"));
}
::StringCchCat(szBuf, _countof(szBuf), TEXT("\n"));
MessageBox(szBuf, TEXT("个人简介汇总"), MB_OK);
}