win32-创建透明的图片按钮

// Test_CustomButton.cpp : Defines the entry point for the application.
//

#include "framework.h"
#include "Test_CustomButton.h"
#include <commctrl.h>
#include <system_error>

#pragma comment (lib,"Comctl32.lib")

#define MAX_LOADSTRING 100
#define IDC_OWNERDRAWBUTTON 101
#define CRAPPY 567

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK OwnerDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

void SetLayeredWindowFromBitmapResource(
    HWND hwnd, UINT bitmapResourceId, HINSTANCE hInstance = nullptr)
{
    DWORD exStyle = ::GetWindowLong(hwnd, GWL_EXSTYLE);

    SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);

    struct Resources {
        HBITMAP hImage = nullptr;
        HGDIOBJ hOldImage = nullptr;
        HDC hMemDC = nullptr;
        ~Resources()
        {
            if (hMemDC)
            {
                if (hOldImage)
                    ::SelectObject(hMemDC, hOldImage);
                ::DeleteDC(hMemDC);
            }
            if (hImage)
                ::DeleteObject(hImage);
        }
    } res;

    if (!hInstance)
        hInstance = ::GetModuleHandle(nullptr);

    res.hImage = reinterpret_cast<HBITMAP>(::LoadImage(
        hInstance, MAKEINTRESOURCE(bitmapResourceId), IMAGE_BITMAP,
        0, 0, LR_CREATEDIBSECTION));

    BITMAP imgInfo{ 0 };
    GetObject(res.hImage, sizeof(imgInfo), &imgInfo);    

    res.hMemDC = ::CreateCompatibleDC(nullptr);   
    res.hOldImage = ::SelectObject(res.hMemDC, res.hImage);

    // Assign the image to the child window, making it transparent.
    SIZE size{ imgInfo.bmWidth, imgInfo.bmHeight };
    POINT ptSrc{ 0, 0 };
    BLENDFUNCTION blend{ AC_SRC_OVER, 0, 200, AC_SRC_ALPHA };
    UpdateLayeredWindow(hwnd, nullptr, nullptr, &size, res.hMemDC, &ptSrc,
        0, &blend, ULW_ALPHA);

    // Destructor of res object will cleanup resources here!
}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_TESTCUSTOMBUTTON, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTCUSTOMBUTTON));

    MSG msg;

    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTCUSTOMBUTTON));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_TESTCUSTOMBUTTON);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);  

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    switch (message)
    {
    case WM_CREATE:
    {
        HWND hButton = CreateWindowEx(0, L"button", NULL, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 150, 50, 80, 80, hWnd, (HMENU)IDC_OWNERDRAWBUTTON, hInst, NULL);
        SetWindowSubclass(hButton, &OwnerDrawButtonProc, IDC_OWNERDRAWBUTTON, 0);
    }
    break;
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // Used be test
            HPEN hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
            SelectObject(hdc, hPen);          
            MoveToEx(hdc, 150, 150, NULL);  
            LineTo(hdc, 200, 60);
            LineTo(hdc, 250, 150);
            LineTo(hdc, 150, 150);
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

LRESULT CALLBACK OwnerDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (uMsg)
    {        
    case WM_PAINT:
    {
        RECT rc;
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        SetLayeredWindowFromBitmapResource(hWnd, IDB_BITMAP1);
        EndPaint(hWnd, &ps);
        return 0;
    }
    case WM_NCDESTROY:
        RemoveWindowSubclass(hWnd, &OwnerDrawButtonProc, 1);
        break;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

注意:

在测试时,我发现需要满足以下条件:

  • 要加载的图像必须是32 bpp的,具有预乘alpha通道的自上而下的位图(可以使用PixelFormer工具转换)。 

          在PixelFormer中,依次转到“文件”,“导入”并选择您的文件(在我的情况下为透明png圆圈)。接下来转到“导出”,然后选择bmp位图(它将显示Windows位图)。完成此操作后,将已经选择了A8:R8:G8:B8(32bpp),接下来必须选中最后两个框“预乘Alpha”和            “自上而下的行顺序”。

          这是我的32 bpp图像供您测试。

  • 需要添加一个清单文件,您可以自己创建一个.manifest文件。然后将其添加到编译器中。

          因为从win 8开始,WS_EX_LAYERED可用于子控件。

          方法:需要清单文件来指定至少Windows 8兼容性(仅Windows 8支持子层)。

          参考:针对Windows的应用程序

  • 您只需要将WS_EX_LAYERED样式添加到子控件中,因为您的要求是使按钮透明。

清单文件代码:

<!-- example.exe.manifest -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <assemblyIdentity
        type="win32"
        name="Contoso.ExampleApplication.ExampleBinary"
        version="1.2.3.4"
        processorArchitecture="x86"
    />
    <description>Contoso Example Application</description>
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <!-- Windows 10 -->
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
            <!-- Windows 8.1 -->
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <!-- Windows 8 -->
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <!-- Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <!-- Windows Vista -->
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
        </application>
    </compatibility>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <!--
                  UAC settings:
                  - app should run at same integrity level as calling process
                  - app does not need to manipulate windows belonging to
                    higher-integrity-level processes
                  -->
                <requestedExecutionLevel
                    level="asInvoker"
                    uiAccess="false"
                />   
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

最后的效果:

win32-创建透明的图片按钮

原文链接: https://www.cnblogs.com/strive-sun/p/12750045.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    win32-创建透明的图片按钮

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404930

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月25日 下午4:48
下一篇 2023年4月25日 下午4:48

相关推荐