简体   繁体   English

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

[英]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. 我有一个背景为蓝色的win32窗口。 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 我使用代码将.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);

Now the button is displayed with transparent .png image data with button default background color. 现在,该按钮将显示具有透明.png图像数据的按钮默认背景色。 I changed the button background color to blue. 我将按钮背景色更改为蓝色。 But when we load .png file , then button color changed to default color. 但是当我们加载.png文件时,按钮颜色将更改为默认颜色。

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. AFAIK没有简单的方法可以使按钮的背景透明并只绘制图标。

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. 也有“所有者绘制”,但是对于按钮,此技术从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. 自定义绘图的优点是您不必修改按钮样式(例如,可以保留BS_DEFPUSHBUTTON ),并且它也更加灵活,因为您只需要做部分绘图即可。 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. 要使用自定义绘制 ,请在按钮父级的窗口过程中处理NM_CUSTOMDRAW通知 When NMCUSTOMDRAW::dwDrawStage equals CDDS_PREERASE , do your drawing and return CDRF_SKIPDEFAULT so Windows doesn't paint over what you have drawn. NMCUSTOMDRAW::dwDrawStage等于CDDS_PREERASE ,请执行绘制并返回CDRF_SKIPDEFAULT以便Windows不会在绘制的内容上进行绘制。

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. 为了实现透明,可以在调用DrawIconEx()在背景上透明绘制图标之前,调用DrawThemeParentBackground()绘制父窗口的背景。

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"): 这是我的按钮图片(“ test.png”):

按钮图片

And this is how the final result looks like: 最终结果如下所示:

窗口截图

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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