简体   繁体   中英

How to display transparent png image files on a win32 button with color same as background color

I have a win32 window with background color blue. I have created a button on the window using the code

// code for creating button

hButton1= CreateWindow(_T("BUTTON"),_T("Test button"), BS_ICON  | WS_VISIBLE | WS_CHILD ,800,200,228,228,hWnd, (HMENU)1,NULL,NULL);

I loaded a .png transparent image as button image using the code

// code to     
// using GDI
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);   

Gdiplus::Bitmap* m_pBitmap;
HICON hicon;
    m_pBitmap = Gdiplus::Bitmap::FromFile(L"d:\\gear.png");
    m_pBitmap->GetHICON(&hicon);  
    LRESULT lr = SendMessage(hButton1,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hicon );

ShowWindow(hButton1,SW_SHOW);

Now the button is displayed with transparent .png image data with button default background color. I changed the button background color to blue. But when we load .png file , then button color changed to default color.

I need to keep the transparent area of the button the same color as the background color of the window ie blue. You can refer the image of my window

这是显示的窗口

AFAIK there is no simple way to make the background of a button transparent and let it only draw the icon.

One can use custom draw to completely control the appearance of the button. There is also "owner draw" but for buttons this technique is outdated as of Windows Vista. Custom draw has the advantage that you don't have to modify the button styles (so you can keep BS_DEFPUSHBUTTON , for instance) and it is also more flexible as you only need to do part of the drawing if you wish so. For our use case we need to draw everything though.

To use custom draw , handle the NM_CUSTOMDRAW notification in the window procedure of the parent of the button. When NMCUSTOMDRAW::dwDrawStage equals CDDS_PREERASE , do your drawing and return CDRF_SKIPDEFAULT so Windows doesn't paint over what you have drawn.

To achieve transparency, one can call DrawThemeParentBackground() to draw the background of the parent window before calling DrawIconEx() to draw the icon transparently over the background.

Example

Here is a complete working example program. Error handling omitted for clarity.

#include <windows.h>
#include <gdiplus.h>
#include <uxtheme.h>  // for DrawThemeParentBackground()

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "uxtheme.lib")

// Common controls manifest entry is required for using custom draw.
// Remove this pragma if you have already included this in the manifest of your project.
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CustomDrawButton( HWND hWnd, NMCUSTOMDRAW const& nmc );

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    // Initialize GDI+
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup( &gdiplusToken, &gdiplusStartupInput, NULL );   

    // Register window class for main window    
    WNDCLASS wc{ sizeof(wc) }; // set cbSize and zero-init all other members
    wc.lpfnWndProc    = WndProc;
    wc.hInstance      = hInstance;
    wc.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wc.hbrBackground  = CreateSolidBrush( RGB( 255, 200, 127 ) );
    wc.lpszClassName  = L"MyWindowClass";
    RegisterClassW( &wc );

    // Create main window    
    HWND hWnd = CreateWindowExW( 0, wc.lpszClassName, L"Test", WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, nullptr );
    ShowWindow( hWnd, nCmdShow );

    // Create button    
    HWND hButton1 = CreateWindow( L"BUTTON", L"Test button", BS_ICON | WS_VISIBLE | WS_CHILD, 50, 50, 228, 228, hWnd, (HMENU) 1, NULL, NULL );

    // Assign image to button
    Gdiplus::Bitmap* m_pBitmap;
    HICON hicon;
    m_pBitmap = Gdiplus::Bitmap::FromFile(L"test.png");
    m_pBitmap->GetHICON(&hicon);  
    LRESULT lr = SendMessage( hButton1, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon );

    // Standard message loop        
    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_NOTIFY:
        {
            auto pnm = reinterpret_cast<LPNMHDR>( lParam );
            if( pnm->code == NM_CUSTOMDRAW )
            {
                // NOTE: you should check if pnm->hwndFrom really is the button
                // you want to draw. Not required in this example because
                // we only have one control.
                LRESULT res = CustomDrawButton( pnm->hwndFrom, *reinterpret_cast<LPNMCUSTOMDRAW>( lParam ) );
                if( res != 0 )
                    return res;
            }
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}   

LRESULT CustomDrawButton( HWND hWnd, NMCUSTOMDRAW const& nmc )
{
    switch( nmc.dwDrawStage )
    {
        case CDDS_PREERASE:
        {
            RECT rc{}; GetClientRect( hWnd, &rc );

            // Draw the background of the parent window.
            DrawThemeParentBackground( hWnd, nmc.hdc, &rc );

            // Get the icon we assigned to the button.    
            HICON hIcon = reinterpret_cast<HICON>( SendMessage( hWnd, BM_GETIMAGE, IMAGE_ICON, 0 ) );

            // Draw the icon transparently over the background.
            DrawIconEx( nmc.hdc, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL );

            // Tell Windows we have drawn everything by ourselfs.    
            return CDRF_SKIPDEFAULT;
        }
    }
    return 0;
}

This is my button image ("test.png"):

按钮图片

And this is how the final result looks like:

窗口截图

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM