Fenying

Angus’ Home.


20 Jul 2011

Windows 标准控件:按钮控件的使用

该文章迁移自作者的旧博客站点。
源地址:http://fenying.blog.163.com/blog/static/102055993201162092619233/

本文展示 Windows 标准控件之按钮控件的使用方法。

以下程序在 Windows 7 简体中文破解版、Visual C++ 2008 专业版、Windows 7 SDK 环境下编译通过。

/* File Begin */
// wTest.cpp : 定义应用程序的入口点。
// This is a Win32 Application C Project.
// Author: Fenying
// Time: 2011-07-20
// Version: 0.0.0.1
// (C) Maple Knights & Fenying Studio Reserved.
// Description: Windows 7 Ultimate SP1 & Visual C++ 2008 Pro & Windows 7 SDK & Win32 Application C Project are required.

#include <tchar.h>
#include <Windows.h>
#include <CommCtrl.h>

#ifdef NULL
    #undef NULL
    #define NULL 0
#else
    #define NULL 0
#endif

//[0] 使用系统主题
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

//[A] 全局变量:
HINSTANCE hInst;                                // 当前实例
LPCTSTR szTitle;                                // 标题栏文本
LPCTSTR szWindowClass;                          // 主窗口类名
HWND hBtnO;                                     // 第一个按钮句柄
HFONT hForeFont;                                // 默认字体

//[B] 此代码模块中包含的函数的前向声明:
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void SetFont(HWND hWndDst);
HWND CreateButton(DWORD dwStyle, LPCTSTR pTitle, HWND hParent, INT x, INT y, INT width, INT height, WORD wID);

//[C] 宏常量

#define GLOBAL_FORE_FONT_NAME        _T("Tahoma")
#define BTN_PUSHBUTTON               1
#define BTN_DEFPUSHBUTTON            2
#define BTN_CHECKBOX                 3
#define BTN_AUTOCHECKBOX             4
#define BTN_3STATECHECKBOX           5
#define BTN_AUTO3STATECHECKBOX       6
#define BTN_GROUPBOX                 7
#define BTN_RADIOBOX                 8
#define BTN_AUTORADIOBOX             9
#define BTN_COMMNADLINK              10
#define BTN_DEFCOMMNADLINK           11
#define BTN_SPLITBUTTON              12
#define BTN_DEFSPLITBUTTON           13

//[D] 主函数
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {

    MSG msg;
    WNDCLASSEX wcex;
    HWND hWnd;

    // 初始化字符串
    szWindowClass = _T("my_wnd_cls");
    szTitle = _T("Hello World");

    // 初始化默认字体
    hForeFont = CreateFontW(14,0,0,0,0,0,0,0,DEFAULT_CHARSET,0,0,0,0, GLOBAL_FORE_FONT_NAME);

    // 注册窗口类
    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc      = 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;

    RegisterClassEx(&wcex);

    // 创建窗体
    hInst = hInstance; // 将实例句柄存储在全局变量中

    hWnd = CreateWindow(szWindowClass, szTitle, WS_TABSTOP|WS_OVERLAPPEDWINDOW, 200, 0, 800, 600, NULL, NULL, hInstance, NULL);

    if (!hWnd) {
        MessageBox(NULL,_T("Failed to create a window."), szTitle, MB_OK);
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    // 主消息循环:
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

//[E] 消息回调函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    int wmId, wmEvent;
    HWND hCtl;

    switch (uMsg) {
    case WM_CREATE: // 当窗体被创建时

        // 创建一个标准命令按钮 Push Button
        hBtnO = CreateButton(BS_PUSHBUTTON, _T("Button"), hWnd, 50, 50, 200, 32, BTN_PUSHBUTTON);

        // 创建一个缺省标准命令按钮 Default Push Button
         CreateButton(BS_DEFPUSHBUTTON, _T("Default Button"), hWnd, 50, 85, 200, 32, BTN_DEFPUSHBUTTON);

        // 创建一个二态复选框 CheckBox,其被单击时不会自动改变选择状态
        CreateButton(BS_CHECKBOX, _T("CheckBox"), hWnd, 50, 120, 200, 24, BTN_CHECKBOX);

        // 创建一个二态自动复选框 Auto CheckBox,其被单击时会自动改变选择状态
        CreateButton(BS_AUTOCHECKBOX, _T("Auto CheckBox"), hWnd, 50, 150, 200, 24, BTN_AUTOCHECKBOX);

        // 创建一个三态复选框 3 State CheckBox,其被单击时不会自动改变选择状态
        CreateButton(BS_3STATE, _T("3 State CheckBox"), hWnd, 50, 180, 200, 24, BTN_3STATECHECKBOX);

        // 创建一个三态自动复选框 Auto 3 State CheckBox,其被单击时会自动改变选择状态
        CreateButton(BS_AUTO3STATE, _T("Auto 3 State CheckBox"), hWnd, 50, 210, 200, 24, BTN_AUTO3STATECHECKBOX);

        // 创建一个组合框 Group Box
        CreateButton(BS_GROUPBOX, _T("Group Box"), hWnd, 50, 240, 200, 100, BTN_GROUPBOX);

        // 创建一个单选框 Radio Box,其被单击时不会自动改变选择状态
        CreateButton(BS_RADIOBUTTON, _T("Radio Box"), hWnd, 50, 350, 200, 24, BTN_RADIOBOX);

        // 创建一个自动单选框 Auto Radio Box,其被单击时会自动改变选择状态
        CreateButton(BS_AUTORADIOBUTTON, _T("Auto Radio Box"), hWnd, 50, 380, 200, 24, BTN_AUTORADIOBOX);

        // 创建一个自动单选框 Auto Radio Box,其被单击时会自动改变选择状态
        CreateButton(BS_AUTORADIOBUTTON, _T("Auto Radio Box"), hWnd, 50, 410, 200, 24, BTN_AUTORADIOBOX);

        // Windows Vista Required.
#if _WIN32_WINNT >= 0x600

        // 创建一个命令链接按钮 Command Link
        CreateButton(BS_COMMANDLINK, _T("Command Link"), hWnd, 300, 50, 200, 48, BTN_COMMNADLINK);

        // 创建一个缺省命令链接按钮 Def Command Link
        CreateButton(BS_DEFCOMMANDLINK, _T("Def Command Link"), hWnd, 300, 100, 200, 48, BTN_DEFCOMMNADLINK);

        // 创建一个分割按钮 Split Button
        CreateButton(BS_SPLITBUTTON, _T("Split Button"), hWnd, 300, 150, 200, 48, BTN_SPLITBUTTON);

        // 创建一个缺省分割按钮 Def Split Button
        CreateButton(BS_DEFSPLITBUTTON, _T("Def Split Button"), hWnd, 300, 200, 200, 48, BTN_DEFSPLITBUTTON);

#endif
        //

        break;

    case WM_COMMAND:  //控件事件
        hCtl    = (HWND)lParam;
        wmId    = LOWORD(wParam); // wParam 的低字表示控件标识,即 CreateWindowEx 函数的 hMenu 参数
        wmEvent = HIWORD(wParam); // wParam 的高字表示控件事件
        if (lParam)
            switch (wmId) {
            case BTN_PUSHBUTTON:    //命令按钮的事件
                switch (wmEvent) {
                case BN_CLICKED: // 单击事件。
                    /*******************************************************
                     * 单击事件消息。
                     *******************************************************/
                    MessageBox(hWnd, _T("Hi, You clicked the command button"), szTitle, MB_OK);
                    break;
                case BN_DOUBLECLICKED:
                    /*******************************************************
                     * 双击事件消息。
                     * 此消息不能和 BN_CLICKED 同时处理,否则无法接收此消息。
                     * BS_USERBUTTON, BS_RADIOBUTTON, BS_OWNERDRAW 三种按钮可
                     * 以自动支持此消息,其他按钮必须添加 BS_NOTIFY 样式。
                     *******************************************************/
                    MessageBox(hWnd, _T("Hi, You double clicked the command button"), szTitle, MB_OK);
                    break;
                default:
                    goto onNothing;
                }
                break;

            case BTN_DEFPUSHBUTTON:    //缺省命令按钮的事件
                switch (wmEvent) {
                case BN_CLICKED: // 单击事件。
                    switch (SendMessage(hBtnO, BM_GETSTATE, 0, 0)) {
                    /*******************************************************
                     * BM_GETSTATE - 获取 Push Button 的状态,
                     * 返回值取如下值:
                     *    BST_PUSHED       -    已按下
                     *    BST_UNCHECKED    -    未按下
                     *******************************************************/
                    case BST_PUSHED:
                        SendMessage(hBtnO, BM_SETSTATE, BST_UNCHECKED, 0);
                    /*******************************************************
                     * BM_SETSTATE - 设置 Push Button 的状态,
                     * 其第三个参数 wParam 决定按钮的状态
                     *    BST_PUSHED       -    已按下
                     *    BST_UNCHECKED    -    未按下
                     *******************************************************/
                        break;
                    case BST_UNCHECKED:
                        SendMessage(hBtnO, BM_SETSTATE, BST_PUSHED, 0);
                        break;
                    default:
                        goto onNothing;
                    }
                    break;
                default:
                    goto onNothing;
                }
                break;

            case BTN_COMMNADLINK: //命令链接按钮
                switch (wmEvent) {
                case BN_CLICKED: // 单击事件。
                    MessageBox(hWnd, _T("Hi, You clicked the default command button"), szTitle, MB_OK);
                    break;
                default:
                    goto onNothing;
                }
                break;


            case BTN_CHECKBOX:    //二态复选框的事件
                switch (wmEvent) {
                case BN_CLICKED:
                    switch (SendMessage(hCtl, BM_GETCHECK, 0, 0)) {
                        /*******************************************************
                         * BM_GETCHECK - 获取单/复选框选中状态
                         * 其返回值可取如下:
                         *    BST_CHECKED          -    已选中状态
                         *    BST_UNCHECKED        -    未选中状态
                         *    BST_INDETERMINATE    -    默认选中状态(三态复选框支持)
                         *******************************************************/
                    case BST_CHECKED:
                        SendMessage(hCtl, BM_SETCHECK, BST_UNCHECKED, 0); //设置为灰色钩
                        /*******************************************************
                         * BM_SETCHECK - 设置单/复选框选中状态
                         * 其第三个参数 wParam 可取如下值作为单/复选框的选中状态:
                         *    BST_CHECKED          -    已选中状态
                         *    BST_UNCHECKED        -    未选中状态
                         *    BST_INDETERMINATE    -    默认选中状态(三态复选框支持)
                         *******************************************************/
                        break;
                    case BST_UNCHECKED: //未选中时
                        SendMessage(hCtl, BM_SETCHECK, BST_CHECKED, 0);
                        break;
                    default:
                        goto onNothing;
                    }
                    break;
                case BN_SETFOCUS:
                    /*******************************************************
                     * BN_SETFOCUS - 获取焦点通知
                     * 当一个按钮具有 BS_NOTIFY 时,如果获得了焦点,会收到此
                     * 通知消息。
                     *******************************************************/
                    SetWindowText(hCtl, _T("With Focus."));
                    break;
                case BN_KILLFOCUS:
                    /*******************************************************
                     * BN_KILLFOCUS - 失去焦点通知
                     * 当一个按钮具有 BS_NOTIFY 时,如果失去了焦点,会收到此
                     * 通知消息。
                     *******************************************************/
                    SetWindowText(hCtl, _T("Without Focus."));
                    break;
                default:
                    goto onNothing;
                }
                break;

            case BTN_3STATECHECKBOX: //三态复选框的事件
                switch (wmEvent) {
                case BN_CLICKED:
                    switch (SendMessage(hCtl, BM_GETCHECK, 0, 0)) {
                    case BST_CHECKED: // 选中时
                        SendMessage(hCtl, BM_SETCHECK, BST_INDETERMINATE, 0); // 设置为灰色钩
                        break;
                    case BST_UNCHECKED: // 未选中时
                        SendMessage(hCtl, BM_SETCHECK, BST_CHECKED, 0); // 设置为选中
                        break;
                    case BST_INDETERMINATE: //灰色钩子时,这个灰色钩子必须有 BS_AUTO3STATE 的样式
                        SendMessage(hCtl, BM_SETCHECK, BST_UNCHECKED, 0); // 设置为未选中
                        break;
                    default:
                        goto onNothing;
                    }
                    break;
                default:
                    goto onNothing;
                }
                break;

            case BTN_RADIOBOX: //单选框的事件
                switch (wmEvent) {
                case BN_CLICKED:
                    switch (SendMessage(hCtl, BM_GETCHECK, 0, 0)) {
                    case BST_CHECKED: // 选中时
                        SendMessage(hCtl, BM_SETCHECK, BST_UNCHECKED, 0); // 设置为灰色钩
                        break;
                    case BST_UNCHECKED: // 未选中时
                        SendMessage(hCtl, BM_SETCHECK, BST_CHECKED, 0); // 设置为选中
                        break;
                    default:
                        goto onNothing;
                    }
                    break;
                default:
                    goto onNothing;
                }
                break;

            default:
                goto onNothing;
            }
        // 分析菜单选择:
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        goto onNothing;
    }
    return 0;
onNothing:
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

//[F] 设置字体
void SetFont(HWND hWndDst) {
    PostMessage(hWndDst, WM_SETFONT, (WPARAM)hForeFont, 1);
}

//[G] 创建按钮控件
HWND CreateButton(DWORD dwStyle, LPCTSTR pTitle, HWND hParent, INT x, INT y, INT width, INT height, WORD wID) {
    HWND hTmp;
    if (hTmp =  CreateWindowEx(NULL, WC_BUTTON, pTitle, BS_NOTIFY|WS_TABSTOP|WS_CHILD|WS_VISIBLE| dwStyle, x, y, width, height, hParent, (HMENU)wID, hInst, NULL))
        SetFont(hTmp);

    return hTmp;
}

/* File End */
该文章根据 CC-BY-4.0 协议发表,转载请遵循该协议。
本文地址:https://fenying.net/post/2011/07/20/windows-sdk-command-button/

comments powered by Disqus