2013-01-14 63 views
0

我试图用半透明像素创建非矩形窗口。该图像不是来自PNG,而是使用GDI +调用即时绘制的。使用UpdateLayeredWindow绘制部分透明的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); 
} 

代码的注释片保存位图对象的PNG,其中我写只是为了确认位图是否正确绘制。

没有发生错误,但屏幕上的结果并不是我的意图。而不是一个很好的50%透明的绿色广场,我得到一个几乎看不见的白色正方形:screenshot

另一个奇怪的是,在窗口坠落点击进入什么是下,尽管它已经是稍微可见......

我在做什么错在这里?

回答

0

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

0

UpdateLayeredWindow()的源位图必须与屏幕兼容,否则您的视觉效果与硬件有关。 GDI和GDIplus似乎可以绘制成任何位图,但bitblt操作通常不能处理不同(即不兼容)的格式。原因是速度。不幸的是,Windows文档没有很清楚地指出这些事实。