【问题标题】:Drawing a partially transparent GDI+ Bitmap to a borderless window using UpdateLayeredWindow使用 UpdateLayeredWindow 将部分透明的 GDI+ 位图绘制到无边框窗口
【发布时间】:2015-03-06 17:59:48
【问题描述】:

我正在尝试创建一个具有半透明像素的非矩形窗口。图片并非来自 PNG,而是使用 GDI+ 调用即时绘制的。

我按如下方式创建窗口:

WNDCLASSEX wc = WNDCLASSEX();
wc.cbSize = sizeof(wc);
HINSTANCE instance = GetModuleHandle(nullptr);
std::wstring classname(L"gditest ui window class");

if (!GetClassInfoEx(instance, classname.c_str(), &wc)) {
    //wc.cbSize;
    //wc.style = CS_DROPSHADOW;
    wc.lpfnWndProc = process_messages;
    //wc.cbClsExtra;
    //wc.cbWndExtra;
    wc.hInstance = instance;
    wc.hIcon;
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    //wc.hbrBackground;
    //wc.lpszMenuName;
    wc.lpszClassName = classname.c_str();
    wc.hIconSm;

    if (!RegisterClassEx(&wc))
        throw GetLastError();
}

m_window = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_LAYERED,
    classname.c_str(), L"User Interface",
    WS_VISIBLE,
    CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
    HWND_DESKTOP, 0, instance, this);

if (!m_window)
    throw GetLastError();

update_window();

update_window() 函数如下所示:

void user_interface::update_window()
{
    RECT r;
    GetClientRect(m_window, &r);

    Bitmap buf(r.right - r.left, r.bottom - r.top, PixelFormat32bppARGB);

    Graphics gfx(&buf);
    Rect rect(r.left, r.top, r.right - r.left, r.bottom - r.top);
    SolidBrush b(Color(0x7f00ff00));
    gfx.FillRectangle(&b, rect);

/*  CLSID clsid;
    UINT numbytes = 0, numenc = 0;
    GetImageEncodersSize(&numenc, &numbytes);

    std::vector<char> encoders(numbytes, 0);
    ImageCodecInfo *encoderptr = (ImageCodecInfo *)&encoders[0];
    GetImageEncoders(numenc, numbytes, encoderptr);

    clsid = encoderptr[4].Clsid;

    buf.Save(L"test.png", &clsid);
*/
    HDC gfxdc = gfx.GetHDC();
    HDC scrndc = GetDC(HWND_DESKTOP);

    BLENDFUNCTION blend;
    blend.BlendOp = AC_SRC_OVER;
    blend.BlendFlags = 0;
    blend.SourceConstantAlpha = 255;
    blend.AlphaFormat = AC_SRC_ALPHA;

    POINT src = POINT(), dst;
    SIZE size;

    GetWindowRect(m_window, &r);
    dst.x = r.left;
    dst.y = r.top;
    size.cx = buf.GetWidth();
    size.cy = buf.GetHeight();

    if (!UpdateLayeredWindow(m_window, scrndc, &dst, &size, gfxdc, &src, 0, &blend, ULW_ALPHA)) {
        throw GetLastError();
    }

    ReleaseDC(HWND_DESKTOP, scrndc);
    gfx.ReleaseHDC(gfxdc);
}

注释的代码段将 Bitmap 对象保存为 PNG,我编写它只是为了确认位图绘制正确。

没有发生错误,但是屏幕上的结果不是我想要的。我得到一个几乎看不见的白色方块,而不是一个漂亮的 50% 透明绿色方块:。

另一个奇怪的事情是,点击窗口会掉到下面的任何东西,尽管它有点可见......

我在这里做错了什么?

【问题讨论】:

    标签: c++ windows gdi+


    【解决方案1】:

    自己通过重写 update_window() 方法来解决这个问题:

    void user_interface::update_window()
    {
        RECT r;
        GetClientRect(m_window, &r);
    
        HDC scrndc = GetDC(HWND_DESKTOP);
        HDC memdc = CreateCompatibleDC(scrndc);
        HBITMAP bmp = CreateCompatibleBitmap(scrndc, r.right - r.left, r.bottom - r.top);
        HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, bmp);
    
        Graphics gfx(memdc);
        Rect rect(r.left, r.top, r.right - r.left, r.bottom - r.top);
        SolidBrush b(Color(0x7f00ff00));
        gfx.FillRectangle(&b, rect);
    
        BLENDFUNCTION blend;
        blend.BlendOp = AC_SRC_OVER;
        blend.BlendFlags = 0;
        blend.SourceConstantAlpha = 255;
        blend.AlphaFormat = AC_SRC_ALPHA;
    
        POINT src = POINT(), dst;
        SIZE size;
    
        size.cx = r.right - r.left;
        size.cy = r.bottom - r.top;
    
        GetWindowRect(m_window, &r);
        dst.x = r.left;
        dst.y = r.top;
    
        if (!UpdateLayeredWindow(m_window, scrndc, &dst, &size, memdc, &src, 0, &blend, ULW_ALPHA)) {
            throw GetLastError();
        }
    
        SelectObject(memdc, oldbmp);
        DeleteObject(bmp);
        DeleteDC(memdc);
        ReleaseDC(HWND_DESKTOP, scrndc);
    }
    

    可能不是最有效的方法,但它确实有效。可能会使 HBITMAP、memdc 和 Graphics 对象保留更长时间。弄清楚这一点留给读者作为练习。 ;)

    【讨论】:

      【解决方案2】:

      UpdateLayeredWindow() 的源位图必须与屏幕兼容,否则您的视觉效果取决于硬件。 GDI 和 GDIplus 似乎能够绘制 any 位图,但 bitblt 操作通常无法处理不同(即不兼容)格式。原因是速度。

      不幸的是,Windows 文档没有非常清楚地指出这些事实。

      【讨论】:

        猜你喜欢
        • 2019-11-03
        • 2023-04-03
        • 2020-09-12
        • 2013-11-03
        • 2013-11-04
        • 1970-01-01
        • 1970-01-01
        • 2019-10-24
        • 1970-01-01
        相关资源
        最近更新 更多