使用UpdateLayeredWindow将部分透明的GDI +位图绘制到无边框窗口

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

我创build窗口如下:

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%透明的绿色广场,我得到一个几乎看不见的白色正方形: 截图

另一个奇怪的是,窗口上的点击落在下面的任何东西,尽pipe它稍微可见…

我在这里做错了什么?

Solutions Collecting From Web of "使用UpdateLayeredWindow将部分透明的GDI +位图绘制到无边框窗口"

通过重写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对象保持更长的时间。 想象这个是留给读者的一个练习。 ;)

UpdateLayeredWindow()的源位图必须与屏幕兼容,否则你的视觉效果是依赖于硬件的。 GDI和GDIplus似乎可以绘制到任何位图,但bitblt操作通常不能处理不同(即不兼容)的格式。 原因是速度。

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