如何在Win32按钮上以与背景色相同的颜色显示透明的png图像文件 [英] How to display transparent png image files on a win32 button with color same as background color

查看:97
本文介绍了如何在Win32按钮上以与背景色相同的颜色显示透明的png图像文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Win32窗口,背景色为蓝色.我已经使用代码在窗口上创建了一个按钮

 //用于创建按钮的代码hButton1 = CreateWindow(_T("BUTTON"),_ T("Test button"),BS_ICON | WS_VISIBLE | WS_CHILD,800,200,228,228,hWnd,(HMENU)1,NULL,NULL); 

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

 //编码为//使用GDIGdiplusStartupInput 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); 

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

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

解决方案

AFAIK没有简单的方法可以使按钮的背景透明并只绘制图标.

一个人可以使用

这是最终结果的样子:

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 i.e. 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:

这篇关于如何在Win32按钮上以与背景色相同的颜色显示透明的png图像文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆