Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change the background color of a button WinAPI C++

I have searched this many times, but everything I find is MFC. I want it in C++ WinAPI. I know how to change the style of a button control, but I cannot find out how to make a button a different color. So, how can I change the background color of a WinAPI button control using C++? I don't want to do this with a resource file.

Thank you!

like image 262
retsgorf297 Avatar asked Sep 11 '13 15:09

retsgorf297


People also ask

How do I change the background color of a button in MFC?

A simpler way is to use CMFCButton. Add a Member Variable for your Button (with MFC-ClassWizzard) and change it to CMFCButton. Here an example to change the color button in green.

How do I change the background color of my console in C ++?

If you are going to write your program for Windows and you want to change color of text and/or background, use this: SetConsoleTextAttribute (GetStdHandle(STD_OUTPUT_HANDLE), attr); Where attr is a combination of values with | (bitwise OR operator), to choose whther you want to change foreground or background color.


2 Answers

Instead of a link I'll just post a copy from my other post using custom-drawing, similar to alwayslearningnewstuff example:

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

First picture shows when nothing is selected, second shows when first button is selected and was pushed and the last one shows when second button was pushed and the mouse is over it (notice the increase of brightness - cutom hilight). In order to do this, you must catch NM_CUSTOMDRAW message and paint button yourself. And this is how you do it. Also added gradient brush function and some comments.

#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;
}
like image 124
FrogTheFrog Avatar answered Sep 23 '22 18:09

FrogTheFrog


I do not remember the link for the original code, but code bellow helped me in the past to solve the problem you currently face.

Notice that it doesn't have resource file, as you have requested, and is in plain Win32 API.

Study it carefully, everything is commented by the original author.

Hopefully it will help you, as it helped me in the past.

If you have any questions, ask, I will try to answer them.

There are 4 ways, as far as I know, to change the color of the button:

  1. Owner draw ( obvious solution ).

  2. Custom draw ( in my opinion the best solution ).

  3. Subclassing the control ( I do not like it, but it is possible ).

  4. Use bitmaps as your buttons background.

  5. Handling WM_CTLCOLORBTN :

From MSDN :

only owner-drawn buttons respond to the parent window processing this message.

Emphasis is mine. If you plan to use this option read the Remarks section carefully.

Code bellow demonstrates cases 1, 2 and 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);
}
like image 40
AlwaysLearningNewStuff Avatar answered Sep 22 '22 18:09

AlwaysLearningNewStuff