如何在win32按钮上显示透明的png图像文件,其颜色与背景颜色相同

0 c++ winapi button

我有一个背景色为蓝色的win32窗口.我使用代码在窗口上创建了一个按钮

// 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);
Run Code Online (Sandbox Code Playgroud)

我使用代码将.png透明图像加载为按钮图像

// 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);
Run Code Online (Sandbox Code Playgroud)

现在按钮显示透明的.png图像数据,按钮默认背景颜色.我将按钮背景颜色更改为蓝色.但是当我们加载.png文件时,按钮颜色变为默认颜色.

我需要保持按钮的透明区域与窗口的背景颜色相同,即蓝色.你可以参考我窗口的图像

这是显示的窗口

zet*_*t42 6

AFAIK没有简单的方法使按钮的背景透明,只让它绘制图标.

可以使用自定义绘制来完全控制按钮的外观.还有"所有者绘制",但对于按钮,此技术在Windows Vista中已过时.自定义绘图的优点是您不必修改按钮样式(例如,您可以保留BS_DEFPUSHBUTTON),并且它也更灵活,因为您只需要执行部分绘图.对于我们的用例,我们需要绘制所有内容.

要使用自定义绘图,请在按钮父级的窗口过程中处理NM_CUSTOMDRAW通知.当NMCUSTOMDRAW::dwDrawStage等于CDDS_PREERASE,做你的图纸,并返回CDRF_SKIPDEFAULT所以Windows没有油漆过你画什么.

为了实现透明性,可以调用DrawThemeParentBackground()父窗口的背景,然后调用DrawIconEx()在背景上透明地绘制图标.

这是一个完整的工作示例程序.为清楚起见省略了错误处理

#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;
}
Run Code Online (Sandbox Code Playgroud)

这是我的按钮图像("test.png"):

按钮图像

这就是最终结果的样子:

窗口截图