zoukankan      html  css  js  c++  java
  • 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>

    最后的效果:

  • 相关阅读:
    C语言 sprintf 函数 C语言零基础入门教程
    C语言 printf 函数 C语言零基础入门教程
    C语言 文件读写 fgets 函数 C语言零基础入门教程
    C语言 文件读写 fputs 函数 C语言零基础入门教程
    C语言 fprintf 函数 C语言零基础入门教程
    C语言 文件读写 fgetc 函数 C语言零基础入门教程
    C语言 文件读写 fputc 函数 C语言零基础入门教程
    C语言 strlen 函数 C语言零基础入门教程
    Brad Abrams关于Naming Conventions的演讲中涉及到的生词集解
    适配器模式
  • 原文地址:https://www.cnblogs.com/strive-sun/p/12750045.html
Copyright © 2011-2022 走看看