本文介绍了使用UpdateLayeredWindow将部分透明的GDI +位图绘制到无边框窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a non-rectangular window with semi-transparent pixels. The image does not come from a PNG but is drawn on-the-fly using GDI+ calls.

我创建的窗口如下:

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()函数如下所示:

The update_window() function looks like this:

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只是为了确认位图是否正确绘制。

The commented piece of code saves the Bitmap object to a PNG, which I wrote just to confirm the bitmap is drawn properly.

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

No errors occur, however the result on screen is not what I intended. Instead of a nice 50% transparent green square I get a barely visible white square: .

另一个奇怪的事情是,窗口上的点击通过下面的任何内容,尽管它是稍微可见...

Another weird thing is that clicks on the window fall through to whatever is underneath, eventhough it is slightly visible...

我是什么

推荐答案

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

Managed to solve this myself by rewriting the update_window() method as such:

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对象更长时间。把这个看作是读者的练习。 ;)

Probably not the most efficient way to do it, but it works. Could probably keep the HBITMAP, memdc and Graphics object around for longer. Figuring this out is left as an exercise for the reader. ;)

这篇关于使用UpdateLayeredWindow将部分透明的GDI +位图绘制到无边框窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 22:00