透明分层窗口白色 我试图用C++ Win32制作一个分层窗口,但是我对它的绘制或“碰撞”有问题

透明分层窗口白色 我试图用C++ Win32制作一个分层窗口,但是我对它的绘制或“碰撞”有问题,c++,winapi,gdi,C++,Winapi,Gdi,作为参考,我正在尝试显示的图片 这是窗口的基本创建 //window DWORD exFlags = 0; if(m_bTransparent) exFlags |= WS_EX_LAYERED; Create(WS_POPUP, exFlags); std::wstring sPic(L"power-disconnected.png"); m_pAlertPic = m_pPowerMon->GetGPPicMan()->LoadPicture(sPic.c_str()

作为参考,我正在尝试显示的图片

这是窗口的基本创建

//window
DWORD exFlags = 0;
if(m_bTransparent)
    exFlags |= WS_EX_LAYERED;
Create(WS_POPUP, exFlags);

std::wstring sPic(L"power-disconnected.png");
m_pAlertPic = m_pPowerMon->GetGPPicMan()->LoadPicture(sPic.c_str());

// make the window layered when using transparency
if(m_bTransparent && m_pAlertPic != nullptr)
{
    HDC hdcScreen = GetDC(GetHandle());
    HDC hdc = CreateCompatibleDC(hdcScreen);
    HBITMAP hbmpold = (HBITMAP)SelectObject(hdc, m_pAlertPic->GetBuffer());

    POINT dcOffset = {0, 0};
    SIZE size = {ww, wh};

    BLENDFUNCTION bf = {AC_SRC_OVER, 0, (int) (2.55 * 100), AC_SRC_ALPHA}; // blend function combines opacity and pixel based transparency
    UpdateLayeredWindow(GetHandle(), hdcScreen, NULL, &size, hdc, &dcOffset, RGB(255, 255, 255), &bf, ULW_ALPHA);
    SelectObject(hdc, hbmpold);
    DeleteDC(hdc);
    ReleaseDC(GetHandle(), hdcScreen);
}
和消息循环

int WindowAlert::WndProc(Gnaq::WindowBase* pWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg)
   {
   case WM_CLOSE:
       Hide();
       return 1;
   case WM_PAINT:
       // only draw when the widow is not transparent
       // layered window redraw them self
       if(!m_bTransparent)
           m_pCanvas->Draw(m_pGraphics);
       break;
   case WM_LBUTTONUP:
       pWnd->Hide();
       m_bDismised = true;
       break;
   }
   return DefWindowProcW(pWnd->GetHandle(), msg, wParam, lParam);
}

这就是我得到的结果 正如你所看到的,通过这个方法,我得到了白色的边框,实际上应该是完全透明的,但是半透明的部分可以正常工作

这是我尝试过的,给了我一个“有用”的改变。 首先,我尝试添加ULW_COLORKEY标志来隐藏白色

UpdateLayeredWindow(GetHandle(), hdcScreen, NULL, &size, hdc, &dcOffset, RGB(255, 255, 255), &bf, ULW_ALPHA | ULW_COLORKEY);
结果呢。

因此,这隐藏了白色边框,但也隐藏了图片中的所有白色。 我尝试的下一件事是将SetLayeredWindowAttributes与UpdateLayeredWindow结合使用,而不使用ULW_COLORKEY标志

SetLayeredWindowAttributes(GetHandle(), 0xFFFFFF00, 255, LWA_COLORKEY);
同样在窗口过程中启用绘制,如下所示

case WM_PAINT:
    m_pCanvas->Draw(m_pGraphics);
    break;
这样我就可以像这样直观地得到我想要的

但他的方法的问题是,如果整个窗口是可点击的,而仅使用UpdateLayeredWindow,则应该是完全透明的部分才是可点击的。我也觉得最后一种方法更像是一种“黑客”,而不是一种体面的方法


所以我希望有人能告诉我我做错了什么。

第一种方法是正确的。错误在位图中,它没有预乘alpha。第一种方法是正确的。该错误出现在位图中,它没有预乘alpha

这是一个漏洞,您使用的是一个意外情况,即GDI使用24bpp画笔渲染背景,alpha为0,而图像使用32bpp绘制,alpha为255。第二种方法是正确的。您需要为窗口提供与颜色键匹配的默认背景笔刷。不是白色,用洋红色或石灰之类的东西。修改
wcex.hbrBackground=CreateSolidBrush(RGB(255,255,0))时修复WNDCLASSEX.hbrBackground来自
(HBRUSH)(彩色窗口+1)实际上没有区别。我还更改了
UpdateLayeredWindow
UpdateLayeredWindow中的颜色,它希望位图具有预乘alpha。这就是为什么在第一个示例中会出现不需要的白色边框;预乘法会删除这个。你是对的,我对alpha进行了预乘法,现在它像一个符咒一样工作。这是一个黑客,你使用的是一个意外事件,即GDI使用24bpp画笔渲染背景,alpha为0,而图像使用32bpp绘制,alpha为255。第二种方法是正确的。您需要为窗口提供与颜色键匹配的默认背景笔刷。不是白色,用洋红色或石灰之类的东西。修改
wcex.hbrBackground=CreateSolidBrush(RGB(255,255,0))时修复WNDCLASSEX.hbrBackground来自
(HBRUSH)(彩色窗口+1)实际上没有区别。我还更改了
UpdateLayeredWindow
UpdateLayeredWindow中的颜色,它希望位图具有预乘alpha。这就是为什么在第一个示例中会出现不需要的白色边框;预乘运算会消除这个。你是对的,我已经对阿尔法进行了预乘,现在它就像一个符咒。