【问题标题】:Drawing a semi-transparent rectangle in a transparent window在透明窗口中绘制半透​​明矩形
【发布时间】:2021-04-10 18:02:58
【问题描述】:

我在 stackoverflow 中找到了这段代码,它确实使用位图在透明窗口上绘制了一个矩形。但不知何故,我无法改变矩形的透明度。更准确地说,我可以,但它会变暗。就好像位图本身有黑色背景一样。如何使矩形透明?

void paintRect(HDC hdc, RECT dim, COLORREF penCol, COLORREF brushCol, int opacity)
    {
        HDC tempHDC = CreateCompatibleDC(hdc);
    
        BITMAPINFO bitmapInfo;
        ZeroMemory(&bitmapInfo, sizeof(BITMAPINFO));
    
        bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bitmapInfo.bmiHeader.biWidth = dim.right - dim.left;
        bitmapInfo.bmiHeader.biHeight = dim.bottom - dim.top;
        bitmapInfo.bmiHeader.biPlanes = 1;
        bitmapInfo.bmiHeader.biBitCount = 32;
        bitmapInfo.bmiHeader.biCompression = BI_RGB;
        bitmapInfo.bmiHeader.biSizeImage = (dim.right - dim.left) * (dim.bottom - dim.top) * 4;
    
        HBITMAP hBitmap = CreateDIBSection(tempHDC, &bitmapInfo, DIB_RGB_COLORS, NULL, NULL, 0x0);
    
        SelectObject(tempHDC, hBitmap);
        SetDCPenColor(tempHDC, RGB(0, 0, 255));
        SetDCBrushColor(tempHDC, RGB(0, 0, 255));
        FillRect(tempHDC, &dim, CreateSolidBrush(RGB(0, 0, 255)));
    
        BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
        AlphaBlend(hdc, dim.left, dim.top, dim.right, dim.bottom, tempHDC, dim.left, dim.top, dim.right, dim.bottom, blend);
    }

完整代码

#include <Windows.h>

int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);
LRESULT CALLBACK windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    WNDCLASS windowClass {};

    windowClass.lpfnWndProc = windowProc;
    windowClass.hInstance = hInstance;
    windowClass.lpszClassName = L"Keystrokes";
    windowClass.style = CS_NOCLOSE;
    windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);

    if (!RegisterClass(&windowClass))
    {
        return 0;
    }

    HWND hwnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, L"Keystrokes", L"Keystrokes", WS_POPUP, 0, 0, 148, 140, 0, 0, hInstance, 0);

    if (!hwnd)
    {
        return 0;
    }

    SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_COLORKEY);

    ShowWindow(hwnd, nCmdShow);

    MSG msg {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

void paintRect(HDC hdc, RECT dim, COLORREF penCol, COLORREF brushCol, int opacity)
{
    HDC tempHDC = CreateCompatibleDC(hdc);

    BITMAPINFO bitmapInfo;
    ZeroMemory(&bitmapInfo, sizeof(BITMAPINFO));

    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmapInfo.bmiHeader.biWidth = dim.right - dim.left;
    bitmapInfo.bmiHeader.biHeight = dim.bottom - dim.top;
    bitmapInfo.bmiHeader.biPlanes = 1;
    bitmapInfo.bmiHeader.biBitCount = 32;
    bitmapInfo.bmiHeader.biCompression = BI_RGB;
    bitmapInfo.bmiHeader.biSizeImage = (dim.right - dim.left) * (dim.bottom - dim.top) * 4;

    HBITMAP hBitmap = CreateDIBSection(tempHDC, &bitmapInfo, DIB_RGB_COLORS, NULL, NULL, 0x0);

    SelectObject(tempHDC, hBitmap);
    SetDCPenColor(tempHDC, RGB(0, 0, 255));
    SetDCBrushColor(tempHDC, RGB(0, 0, 255));
    FillRect(tempHDC, &dim, CreateSolidBrush(RGB(0, 0, 255)));

    BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
    AlphaBlend(hdc, dim.left, dim.top, dim.right, dim.bottom, tempHDC, dim.left, dim.top, dim.right, dim.bottom, blend);
}

LRESULT CALLBACK windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_LBUTTONDOWN:
        {
            SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
        }
        
        break;

        case WM_MBUTTONDOWN:
        {
            PostQuitMessage(0);
        }

        break;

        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hDC = BeginPaint(hwnd, &ps);

            paintRect(hDC, { 0, 0, 48, 48 }, RGB(255, 0, 0), RGB(255, 255, 255), 255);

            EndPaint(hwnd, &ps);
        }
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

【问题讨论】:

    标签: c++ winapi gdi


    【解决方案1】:

    “好像位图本身有黑色背景一样。”

    因为你的背景设置为:

    windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    

    当然你可以设置成NULL_BRUSH让它看起来透明:

    windowClass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
    

    但是当你移动它的时候,你会发现这并不是让窗口透明,而是停止绘制背景:

    正如@Ben 回答here:

    您还没有使窗口透明,您刚刚停止绘制背景。您所看到的背景只是窗口第一次绘制时发生在窗口下方的任何内容。

    而你需要参考Layered Windows

    不能直接在窗口上添加矩形,应该使用分层窗口,然后添加你需要的。

    这是一个示例,您可以参考它:

    #include <Windows.h>
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    int WINAPI WinMain(_In_  HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_  LPSTR szCmdLine, _In_  int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT("test window");
        HWND hwnd;
        MSG msg;
        WNDCLASS wndclass;
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName = NULL;
        wndclass.lpszClassName = szAppName;
        if (!RegisterClass(&wndclass))
        {
            MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
        }
    
        hwnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, szAppName,
            TEXT("the hello program"),
            WS_POPUP,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            148,
            148,
            NULL,
            NULL,
            hInstance,
            NULL);
        SetLayeredWindowAttributes(hwnd, 0, 1, LWA_ALPHA);
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
        while (GetMessageW(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
        return msg.wParam;
    }
    VOID FadeRect(RECT* prc, HDC hdc)
    {
        BOOL fFade = FALSE;
        static HWND hwnd;
        SIZE size;
        POINT ptSrc = { 0, 0 };
        BLENDFUNCTION blend;
    
        SystemParametersInfo(SPI_GETSELECTIONFADE, 0, &fFade, 0);
        if (!fFade)
            return;
        if (!hwnd) hwnd = CreateWindowEx(WS_EX_LAYERED | 
            WS_EX_TRANSPARENT | 
            WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
            L"static", L"static", WS_POPUP | WS_VISIBLE, prc->left,
            prc->top, prc->right, prc->bottom, NULL, (HMENU)0, NULL, NULL);
        else MoveWindow(hwnd, prc->left, prc->top, prc->right, prc->bottom, TRUE);
    
        RECT rect{ prc->left,prc->top,prc->right,prc->bottom };
        size.cx = prc->right - prc->left;
        size.cy = prc->bottom - prc->top;
    
        blend.BlendOp = AC_SRC_OVER;
        blend.BlendFlags = 0;
        blend.AlphaFormat = 0;
        blend.SourceConstantAlpha = 150;
        UpdateLayeredWindow(hwnd, NULL, NULL, &size, hdc, &ptSrc, 0,
            &blend, ULW_ALPHA);
    }
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_LBUTTONDOWN:
        {
            SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
            InvalidateRect(hwnd, NULL, TRUE);
        }
        break;
        case WM_MBUTTONDOWN:
        {
            PostQuitMessage(0);
        }
    
        break;
    
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            RECT rect;
            GetClientRect(hwnd, &rect);
            MapWindowPoints(hwnd, GetParent(hwnd), (LPPOINT)&rect, 2);
            HDC hDC = BeginPaint(hwnd, &ps);
            RECT rc{ rect.left,rect.top,rect.left + 48,rect.top + 48 };
            FadeRect(&rc, hDC);
            EndPaint(hwnd, &ps);
        }
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        }
    
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    

    【讨论】:

    • 对不起,但我仍然不明白在完全透明的窗口上绘制半透明矩形到底需要做什么。请帮忙。 :(
    • @AugustVishnevsky 我已经更新了我的答案,你可以参考一下。
    • 我需要用位图来做这个。我不明白。对不起。
    猜你喜欢
    • 1970-01-01
    • 2016-05-25
    • 1970-01-01
    • 2012-06-20
    • 2012-01-16
    • 2016-03-12
    • 1970-01-01
    • 2011-08-31
    • 1970-01-01
    相关资源
    最近更新 更多