33_UI子窗口控件多少会一点之按钮类

发布时间:2024年01月17日

UI子窗口控件多少会一点之按钮类

调用CreateWindow() / CreateWindowEx()函数创建窗口的时候,将窗口样式指定为WS_CHILDWS_CHILDWINDOW就可以创建一个子窗口。子窗口的位置可以在父窗口客户区的任何地方,这样的子窗口需要程序注册窗口类并提供窗口过程。程序也可以通过系统预定义的窗口类和窗口过程来创建标准子窗口控件,程序中常见的标准子窗口挫件有按钮、单选按钮、复选按钮、编辑框、组合框、列表框、滚动条控件等,像资源管理器窗口就包含多个子窗口控件,例如工具栏、树视图控件、滚动条控件等。标准子窗口控件也称为通用控件(Common Control) 。

创建按钮对象

程序可以把窗口类名指定为系统预定义的相关子窗口控件类名来调用CreateWindow()/ CreateWindowEx()函数创建一个子窗口控件(对应形参的lpClassName),子窗口控件和父窗口之间可以互相发送消息来进行通信。子窗口控件在对话框程序中用得更普遍,不需要调用CreateWindow()/ CreateWindowEx()函数,直接在资源脚本文件中定义子窗口控件即可,也可以通过资源编辑器从工具箱中拖曳子窗口控件到对话框程序界面的合适位置。

系统预定义的窗口类名字符串含义

  • Button按钮(普通按钮、单选按钮、复选按钮、分组框)
  • Edit编辑框
  • ListBox列表框
  • ComboBox组合框ScrollBar滚动条Static静态控件
  • MDIClientMDl 客户窗口

另外,有一些类名是系统内部使用的,例如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_KTLLFOCUSBS_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_ICONBS_BITMAP样式也可以单独使用,表示在普通按钮上显示一个图标或一副位图。指定BS_ICON或BS_BITMAP样式以后,需要发送BM_SETIMAGE消息为其设置图标或位图,后面再详细解释这个消息。

BS_前缀的样式是按钮专用样式。除了这些按钮专用样式,因为子窗口控件也是一个窗口,所以大部分用于普通窗口的API函数和窗口样式适用于子窗口控件。例如下表的窗口样式可以用于按钮。

含义
WS_CHILDWS_CHILDWINDOW窗口是子窗口
WS_VISIBLEWS_VISABLE窗口最初可见,可以通过调用ShowWindow()SetWindowPos()函数显示和隐藏窗口
WS_GROUPWS_GROUP该窗口是一组控件的第一个控件,该组由第一个具有WS_GROUP样式的控件和在其后定义的所有控件组成,直到下一个具有WS_GROUP样式的控件(不包括该控件)出现。如果是在对话框程序中,用户可以使用方向键将键盘焦点从组中的一个控件移动到下一个控件。另外,每个组中的第一个控件通常具有WS_TABSTOP样式,如果是在对话框程序中,按下Tab键可以将键盘焦点移动到下一个具有WS_TABSTOP样式的按件。
WS_TABSTOP该窗口是一个控件,当用户按下Tab键时,该控件可以接收键盘焦点,如果是在对话框程序中,按下Tab键可以将键盘焦点移动到下一个具有WS_TABSTOP样式的控件上
WS_BORDER窗口有一个细线边框
WS_DLGFRAME窗口具有对话框样式的边框
WS_SIZEBOXWS_THICKFRAME窗口具有大小调整边框
WS_DISABLED窗口最初被禁用,禁用的窗口无法接收用户的输入,要想启用可以调用EnableWindow()函数

其中,WS_CHILDWS_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_ICONBS_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消息用于获取单选按钮、复选框或三态复选框的选中状态.

    • wParamlParam参数没有用到,都指定为0即可
    • 返回值可以是BST_CHECKED (已选中)、BST_UNCHECKED (未选中)或BST_INDETERMINATE(灰色,表示不确定状态,用于三态复选框)。
  • BM_SETSTATE消息用于设置普通按钮是否按下的状态.

    • wParam参数可以指定为TRUE(突出显示,按下状态)或FALSE(取消突出显示,非按下状态)
    • lParam参数没有用到,指定为0即可。
  • BM_GETSTATE消息用于获取普通按钮、单选按钮、复选框或三态复选框的当前状态(选中状态,是否按下和是否具有键盘焦点等)

    • wParamlParam 参数没有用到,都指定为0即可.
    • 返回值可以是BST_CHECKED (已选中)、BST_UNCHECKED(未选中)、BST_INDETERMINATE(灰色,表示不确定状态,用于三态复选框)、BST_PUSHED(普通按钮处于按下状态)、BST_FOCUS(按钮具有键盘焦点)、
      BST_HOT(鼠标悬停在按钮上)、BST_DROPDOWNPUSHED(按钮处于下拉状态,并且仅当按钮具有BTNS_DROPDOWN样式时用于工具栏按钮)。
  • 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消息的wParamIParam参数的含义。

HIWORD (wParam) LOWORD (wParam) HWND(lParam)
菜单命今ID 比如说,ID_MEUN菜单项ID,比如说,记事本程序的打开菜单项IDIDM_FILE_OPEN,保存菜单项IDM_FILE_SAVE0
加速键(快捷键)菜单项ID,同上0
子窗口控件通知码,比如说BN_CLICKED按钮比点击了。控件ID,比如说按钮控件的IDID_BUTTON控件句柄

通知码,可以类比QT中的发出的信号。

   // 为按钮绑定事件 connect(信号的发送者,发送的信号,信号的接受者,处理的函数(槽函数))
    connect(btn, &QPushButton::clicked, this, &QWidget::close);

BN_SETFOCUS: 按钮获得了键盘焦点

BN_KILLFOCUS:按钮失去了键盘焦点

BN_DBLCLKBN_DOUBLECLICKED :双击按钮

获得键盘焦点的按钮周围会显示一圈虚线,此时按下空格键就相当于单击了按钮。只有具有BS_NOTIFY样式的按钮会发送BN_SETFOCUS BN_KILLFOCUSBN_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()函数分别创建了普通按钮、图标按钮、位图按钮、自绘按钮、一组自动单选按钮、一组自动复选按钮、一组自动三态复选按钮、默认按钮。

  • resource.h
//{{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

在MFC中这些类型的按钮都用一个CButton类来表示。同样的WIN32的程序我们也可以用MFC来实现。要实现按钮自绘的话,MFC中通过继承CButton来做。

  • resource.h
    在这里插入图片描述
//{{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

  • HelloMFCDlg.h
#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

// 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);


}

文章来源:https://blog.csdn.net/WNX10086/article/details/135632507
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。