c++ - 在透明窗口中绘制半透​​明矩形

标签 c++ winapi gdi

我在 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);
}

最佳答案

“As if the bitmap itself has a black background.”

因为您的背景设置为:

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

当然你可以将其设置为NULL_BRUSH以使其看起来透明:

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

enter image description here

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

enter image description here

正如 @Ben 的回答 here :

You haven't made the window transparent, you have just stopped drawing the background. What you see as the background is just whatever happened to be underneath the window when it was first drawn.

并且您需要引用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);
}

关于c++ - 在透明窗口中绘制半透​​明矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65571249/

相关文章:

android - 无法加载-android jni

c++ - 使用 cout 打印字符数组的全部内容

c++ - 比较键和值 std::maps

c - 如何激活Windows系统空闲状态?

c++ - C++::在构造函数退出之前通过指针调用Member函数

c++ - 如何获得窗口的颜色

c# - c#上的斜角或凹陷效果算法

c++ - 如何查询正在运行的进程的参数列表? ( window ,C++)

c++ - 使用简单 COM dll 的 UAC 提升

c# - 给定 IntPtr 句柄,更改窗口背景颜色