如何更改按钮WinAPI C ++的背景颜色

时间:2013-09-11 15:33:56

标签: c++ winapi button colors background

我已多次搜索过,但我发现的一切都是MFC。我希望它在C ++ WinAPI中。我知道如何更改按钮控件的样式,但我无法找到如何使按钮成为不同的颜色。那么,如何使用C ++更改WinAPI按钮控件的背景颜色?我不想用资源文件来做这件事。

谢谢!

4 个答案:

答案 0 :(得分:9)

我只是使用自定义绘图从我的其他帖子发布副本而不是链接,类似于alwayslearningnewstuff示例:

Nothing is selected First button is selected and was pushed Second button was pushed and the mouse is over it (notice the increse of brightness - cutom hilight)

第一张图显示当没有选择任何内容时,第二张显示第一个按钮被选中并被按下时,最后一张显示第二个按钮被按下且鼠标悬停在它上面(注意亮度增加 - cutom hilight)。为此,您必须自己捕获NM_CUSTOMDRAW消息和绘制按钮。这就是你如何做到的。还添加了渐变画笔功能和一些注释。

#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 

#include <Windows.h>
#include <Commctrl.h>

#define IDC_EXIT_BUTTON 101
#define IDC_PUSHLIKE_BUTTON 102

HBRUSH CreateGradientBrush(COLORREF top, COLORREF bottom, LPNMCUSTOMDRAW item)
    {
        HBRUSH Brush = NULL;
        HDC hdcmem = CreateCompatibleDC(item->hdc);
        HBITMAP hbitmap = CreateCompatibleBitmap(item->hdc, item->rc.right-item->rc.left, item->rc.bottom-item->rc.top);
        SelectObject(hdcmem, hbitmap);

        int r1 = GetRValue(top), r2 = GetRValue(bottom), g1 = GetGValue(top), g2 = GetGValue(bottom), b1 = GetBValue(top), b2 = GetBValue(bottom);
        for(int i = 0; i < item->rc.bottom-item->rc.top; i++)
        { 
            RECT temp;
            int r,g,b;
            r = int(r1 + double(i * (r2-r1) / item->rc.bottom-item->rc.top));
            g = int(g1 + double(i * (g2-g1) / item->rc.bottom-item->rc.top));
            b = int(b1 + double(i * (b2-b1) / item->rc.bottom-item->rc.top));
            Brush = CreateSolidBrush(RGB(r, g, b));
            temp.left = 0;
            temp.top = i;
            temp.right = item->rc.right-item->rc.left;
            temp.bottom = i + 1; 
            FillRect(hdcmem, &temp, Brush);
            DeleteObject(Brush);
        }
        HBRUSH pattern = CreatePatternBrush(hbitmap);

        DeleteDC(hdcmem);
        DeleteObject(Brush);
        DeleteObject(hbitmap);

        return pattern;
    }

LRESULT CALLBACK MainWindow(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HBRUSH defaultbrush = NULL;
    static HBRUSH hotbrush = NULL;
    static HBRUSH selectbrush = NULL;
    static HBRUSH push_uncheckedbrush = NULL;
    static HBRUSH push_checkedbrush = NULL;
    static HBRUSH push_hotbrush1 = NULL;
    static HBRUSH push_hotbrush2 = NULL;
    switch (msg)
    {
        case WM_CREATE:
            {
                HWND Exit_Button = CreateWindowEx(NULL, L"BUTTON", L"EXIT", 
                                                        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 
                                                        50, 50, 100, 100, hwnd, (HMENU)IDC_EXIT_BUTTON, NULL, NULL);
                if(Exit_Button == NULL)
                    {
                        MessageBox(NULL, L"Button Creation Failed!", L"Error!", MB_ICONEXCLAMATION);
                        exit(EXIT_FAILURE);
                    }

                HWND Pushlike_Button = CreateWindowEx(NULL, L"BUTTON", L"PUSH ME!", 
                                                        WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX | BS_PUSHLIKE, 
                                                        200, 50, 100, 100, hwnd, (HMENU)IDC_PUSHLIKE_BUTTON, NULL, NULL);
                if(Pushlike_Button == NULL)
                    {
                        MessageBox(NULL, L"Button Creation Failed!", L"Error!", MB_ICONEXCLAMATION);
                        exit(EXIT_FAILURE);
                    }
            }
        break;
        case WM_COMMAND:
            {
                switch(LOWORD(wParam))
                    {
                        case IDC_EXIT_BUTTON:
                            {
                                SendMessage(hwnd, WM_CLOSE, 0, 0);
                            }
                        break;
                    }
            }
        break;
        case WM_NOTIFY:
        {
            LPNMHDR some_item = (LPNMHDR)lParam;

            if (some_item->idFrom == IDC_EXIT_BUTTON && some_item->code == NM_CUSTOMDRAW)
            {
                LPNMCUSTOMDRAW item = (LPNMCUSTOMDRAW)some_item;

                if (item->uItemState & CDIS_SELECTED)
                {
                    //Select our color when the button is selected
                    if (selectbrush == NULL)
                        selectbrush = CreateGradientBrush(RGB(180, 0, 0), RGB(255, 180, 0), item);

                    //Create pen for button border
                    HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));

                    //Select our brush into hDC
                    HGDIOBJ old_pen = SelectObject(item->hdc, pen);
                    HGDIOBJ old_brush = SelectObject(item->hdc, selectbrush);

                    //If you want rounded button, then use this, otherwise use FillRect().
                    RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 5, 5);

                    //Clean up
                    SelectObject(item->hdc, old_pen);
                    SelectObject(item->hdc, old_brush);
                    DeleteObject(pen);

                    //Now, I don't want to do anything else myself (draw text) so I use this value for return:
                    return CDRF_DODEFAULT;
                    //Let's say I wanted to draw text and stuff, then I would have to do it before return with
                    //DrawText() or other function and return CDRF_SKIPDEFAULT
                }
                else
                {
                    if (item->uItemState & CDIS_HOT) //Our mouse is over the button
                    {
                        //Select our color when the mouse hovers our button
                        if (hotbrush == NULL)
                            hotbrush = CreateGradientBrush(RGB(255, 230, 0), RGB(245, 0, 0), item);

                        HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));

                        HGDIOBJ old_pen = SelectObject(item->hdc, pen);
                        HGDIOBJ old_brush = SelectObject(item->hdc, hotbrush);

                        RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 5, 5);

                        SelectObject(item->hdc, old_pen);
                        SelectObject(item->hdc, old_brush);
                        DeleteObject(pen);

                        return CDRF_DODEFAULT;
                    }

                    //Select our color when our button is doing nothing
                    if (defaultbrush == NULL)
                        defaultbrush = CreateGradientBrush(RGB(255, 180, 0), RGB(180, 0, 0), item);

                    HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));

                    HGDIOBJ old_pen = SelectObject(item->hdc, pen);
                    HGDIOBJ old_brush = SelectObject(item->hdc, defaultbrush);

                    RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 5, 5);

                    SelectObject(item->hdc, old_pen);
                    SelectObject(item->hdc, old_brush);
                    DeleteObject(pen);

                    return CDRF_DODEFAULT;
                }
            }
            else if (some_item->idFrom == IDC_PUSHLIKE_BUTTON && some_item->code == NM_CUSTOMDRAW)
            {
                LPNMCUSTOMDRAW item = (LPNMCUSTOMDRAW)some_item;

                if (IsDlgButtonChecked(hwnd, some_item->idFrom))
                {
                    if (item->uItemState & CDIS_HOT)
                    {

                        if (push_hotbrush1 == NULL)
                            push_hotbrush1 = CreateGradientBrush(RGB(0, 0, 245), RGB(0, 230, 255), item);

                        HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));

                        HGDIOBJ old_pen = SelectObject(item->hdc, pen);
                        HGDIOBJ old_brush = SelectObject(item->hdc, push_hotbrush1);

                        RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);

                        SelectObject(item->hdc, old_pen);
                        SelectObject(item->hdc, old_brush);
                        DeleteObject(pen);

                        return CDRF_DODEFAULT;
                    }


                    if (push_checkedbrush == NULL)
                        push_checkedbrush = CreateGradientBrush(RGB(0, 0, 180), RGB(0, 222, 200), item);


                    HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));


                    HGDIOBJ old_pen = SelectObject(item->hdc, pen);
                    HGDIOBJ old_brush = SelectObject(item->hdc, push_checkedbrush);


                    RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);


                    SelectObject(item->hdc, old_pen);
                    SelectObject(item->hdc, old_brush);
                    DeleteObject(pen);


                    return CDRF_DODEFAULT;
                }
                else
                {
                    if (item->uItemState & CDIS_HOT)
                    {
                        if (push_hotbrush2 == NULL)
                            push_hotbrush2 = CreateGradientBrush(RGB(255, 230, 0), RGB(245, 0, 0), item);

                        HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));

                        HGDIOBJ old_pen = SelectObject(item->hdc, pen);
                        HGDIOBJ old_brush = SelectObject(item->hdc, push_hotbrush2);

                        RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);

                        SelectObject(item->hdc, old_pen);
                        SelectObject(item->hdc, old_brush);
                        DeleteObject(pen);

                        return CDRF_DODEFAULT;
                    }

                    if (push_uncheckedbrush == NULL)
                        push_uncheckedbrush = CreateGradientBrush(RGB(255, 180, 0), RGB(180, 0, 0), item);

                    HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));

                    HGDIOBJ old_pen = SelectObject(item->hdc, pen);
                    HGDIOBJ old_brush = SelectObject(item->hdc, defaultbrush);

                    RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);

                    SelectObject(item->hdc, old_pen);
                    SelectObject(item->hdc, old_brush);
                    DeleteObject(pen);

                    return CDRF_DODEFAULT;
                }
            }
            return CDRF_DODEFAULT;
        }
        break;
        case WM_CTLCOLORBTN: //In order to make those edges invisble when we use RoundRect(),
            {                //we make the color of our button's background match window's background
                return (LRESULT)GetSysColorBrush(COLOR_WINDOW+1);
            }
        break;
        case WM_CLOSE:
            {
                DestroyWindow(hwnd);
                return 0;
            }
        break;
        case WM_DESTROY:
            {
                DeleteObject(defaultbrush);
                DeleteObject(selectbrush);
                DeleteObject(hotbrush);
                DeleteObject(push_checkedbrush);
                DeleteObject(push_hotbrush1);
                DeleteObject(push_hotbrush2);
                DeleteObject(push_uncheckedbrush);
                PostQuitMessage(0);
                return 0;
            }
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG msg;
    const wchar_t ClassName[] = L"Main_Window";

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = MainWindow;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = ClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
        exit(EXIT_FAILURE);
    }

    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, ClassName, L"Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 368, 248, NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, L"Window Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK);
        exit(EXIT_FAILURE);
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.message;
}

答案 1 :(得分:5)

我不记得原始代码的链接,但是过去的代码帮助我解决了您目前面临的问题。

请注意,它没有您所请求的资源文件,并且是普通的Win32 API。

仔细研究,一切都由原作者评论。

希望它会帮助你,因为它在过去帮助过我。

如果您有任何疑问,请询问,我会尽力回答。

据我所知,有4种方法可以改变按钮的颜色:

  1. 所有者提取(明显的解决方案)。

  2. 自定义抽奖(在我看来是最佳解决方案)。

  3. 子类化控件(我不喜欢它,但有可能)。

  4. 使用位图作为按钮背景。

  5. 处理WM_CTLCOLORBTN

  6.   

    来自MSDN:

         

    只有所有者绘制的按钮才会响应处理此窗口的父窗口   信息。

    重点是我的。如果您打算使用此选项,请仔细阅读Remarks section

    下面的代码演示了案例1,2和4。

    #pragma comment(linker, "/manifestdependency:\"type='win32' \
        name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
        processorArchitecture='*' \
        publicKeyToken='6595b64144ccf1df' language='*'\"")
    
    #pragma comment(lib, "comctl32.lib")
    
    #include <windows.h>
    #include <commctrl.h>
    
    ATOM RegisterWndClass(HINSTANCE hInst);
    
    BOOL CreateMainWnd(HINSTANCE hInstance, int nCmdShow);
    
    LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    
    HINSTANCE hInst;
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hInstPrev, LPWSTR lpszCmdLine, 
        int nCmdShow)
    {
        INITCOMMONCONTROLSEX icex = {0};
        icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
        icex.dwICC  = ICC_LISTVIEW_CLASSES | ICC_USEREX_CLASSES | ICC_BAR_CLASSES |
                      ICC_COOL_CLASSES | ICC_TAB_CLASSES | ICC_WIN95_CLASSES | 
                      ICC_PROGRESS_CLASS | ICC_PAGESCROLLER_CLASS;
    
        InitCommonControlsEx(&icex);
    
        MSG msg;
    
        hInst = hInstance;
    
        if (!RegisterWndClass(hInstance))
           return NULL;
    
        if (!CreateMainWnd(hInstance, nCmdShow))
           return NULL;
    
        while (GetMessage(&msg, NULL, NULL, NULL))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    };
    
    ATOM RegisterWndClass(HINSTANCE hInstance)
    {
    
        WNDCLASS wndClass = {0};
        wndClass.style = CS_DBLCLKS;
        wndClass.lpfnWndProc = MainWndProc;
        wndClass.hInstance = hInstance;
        wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndClass.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = L"MainClass";
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
    
        return RegisterClass(&wndClass);
     }
    
    BOOL CreateMainWnd(HINSTANCE hInstance, int nCmdShow)
    {
        HWND hWnd = CreateWindow(L"MainClass", L"Buttons sample",
             WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
             GetSystemMetrics(SM_CXSCREEN) / 2 - 115,
             GetSystemMetrics(SM_CYSCREEN) / 2 - 50,
             230, 100, NULL, NULL, hInstance, NULL);
    
        if (!hWnd)
            return FALSE;
    
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
        return TRUE;
    }
    
    HBITMAP hBitmap = NULL;
    
    LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
        case WM_CREATE:
            {
                // Owner draw button
    
                CreateWindow(L"BUTTON", L"", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | 
                    BS_OWNERDRAW, 10, 10, 60, 30, hWnd, 
                    (HMENU)10001, hInst, NULL);
    
                // Custom draw button
    
                CreateWindow(L"BUTTON", L"", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 80, 
                    10, 60, 30, hWnd, (HMENU)10002, hInst, NULL);
    
                // Bitmap button
    
                HWND hBitmapButton = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_VISIBLE 
                    | BS_PUSHBUTTON | BS_BITMAP,
                    150, 10, 60, 30, hWnd,
                    (HMENU)10003, hInst, NULL);
    
                HDC hDC = GetDC(hWnd);
    
                HDC hMemDC = CreateCompatibleDC(hDC);
    
                hBitmap = CreateCompatibleBitmap(hDC, 55, 25);
    
                SelectObject(hMemDC, hBitmap);
    
                SetDCBrushColor(hMemDC, RGB(0, 0, 255));
    
                RECT r = {0};
                r.left = 0;
                r.right = 55;
                r.top = 0;
                r.bottom = 25;
    
                FillRect(hMemDC, &r, (HBRUSH)GetStockObject(DC_BRUSH));
    
                DeleteDC(hMemDC);
                ReleaseDC(hWnd, hDC);
    
                SendMessage(hBitmapButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, 
                    (LPARAM)hBitmap);
    
                return 0;
            }
    
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case 10001:
                MessageBox(hWnd, L"Owner draw button clicked", L"Message", NULL);
                return 0;
            case 10002:
                MessageBox(hWnd, L"Custom draw button clicked", L"Message", NULL);
                return 0;
            case 10003:
                MessageBox(hWnd, L"Bitmap button clicked", L"Message", NULL);
                return 0;
            }
            break;
    
        // Owner draw button
    
        case WM_DRAWITEM:
            if (wParam == 10001)
            {
                LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
    
                SetDCBrushColor(lpDIS -> hDC, RGB(255, 0, 0));
    
                SelectObject(lpDIS -> hDC, GetStockObject(DC_BRUSH));
    
                RoundRect(lpDIS -> hDC, lpDIS -> rcItem.left, lpDIS -> rcItem.top,
                    lpDIS -> rcItem.right, lpDIS -> rcItem.bottom, 5, 5);
    
                return TRUE;
            }
            break;
    
        // Custom draw button
    
        case WM_NOTIFY:
            switch (((LPNMHDR)lParam) -> code)
            {
            case NM_CUSTOMDRAW:
                if (((LPNMHDR)lParam) -> idFrom == 10002)
                {
                    LPNMCUSTOMDRAW lpnmCD = (LPNMCUSTOMDRAW)lParam;
    
                    switch (lpnmCD -> dwDrawStage)
                    {
                    case CDDS_PREPAINT:
    
                        SetDCBrushColor(lpnmCD -> hdc, RGB(0, 255, 0));
                        SetDCPenColor(lpnmCD -> hdc, RGB(0, 255, 0));
                        SelectObject(lpnmCD -> hdc, GetStockObject(DC_BRUSH));
                        SelectObject(lpnmCD -> hdc, GetStockObject(DC_PEN));
    
                        RoundRect(lpnmCD -> hdc, lpnmCD -> rc.left + 3, 
                            lpnmCD -> rc.top + 3, 
                            lpnmCD -> rc.right - 3, 
                            lpnmCD -> rc.bottom - 3, 5, 5);
    
                        return TRUE;
                    }
                }
                break;
            }
            break;
    
        case WM_DESTROY:
            if (hBitmap != NULL)
                DeleteObject((HBITMAP)hBitmap);
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    

答案 2 :(得分:3)

您可以在DialogProc(MSDN About WM_DRAWITEM)上的消息WM_DRAWITEM中编辑一个按钮(其标志为BS_OWNERDRAW),这是一个如何绘制简单按钮的简单示例:

LPDRAWITEMSTRUCT Item;
    Item = (LPDRAWITEMSTRUCT)lParam;
    SelectObject(Item->hDC, CreateFont(16, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial Black"));
    FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(0));
    SelectObject(Item->hDC, CreateSolidBrush(0));
    if (Item->itemState & ODS_SELECTED)
    {
        SetTextColor(Item->hDC, 0);
        SelectObject(Item->hDC, CreateSolidBrush(0xFF00));
        SelectObject(Item->hDC, CreatePen(PS_SOLID, 2, 0xFF00));
    }
    else
    {
        SetTextColor(Item->hDC, 0x00FF00);  
        SelectObject(Item->hDC, CreatePen(PS_SOLID, 2, 0x00FF00));

    }
    SetBkMode(Item->hDC, TRANSPARENT);
    RoundRect(Item->hDC, Item->rcItem.left, Item->rcItem.top, Item->rcItem.right, Item->rcItem.bottom, 20, 20);
    int len;
    len = GetWindowTextLength(Item->hwndItem);
    LPSTR lpBuff;
    lpBuff = new char[len+1];
    GetWindowTextA(Item->hwndItem, lpBuff, len+1);
    DrawTextA(Item->hDC, lpBuff, len, &Item->rcItem, DT_CENTER);

答案 3 :(得分:1)

你需要一个owner-drawn button。出于某种原因,与其他控件不同,常规按钮不会对WM_CTLCOLORBTN消息处理程序中的更改做出反应。