【问题标题】:transparency layered window white透明度 分层 窗口 白色
【发布时间】:2013-10-18 12:18:12
【问题描述】:

我正在尝试使用 c++ win32 创建一个分层窗口,但我遇到了绘图问题或它的“冲突”

供参考我要显示的图片。

这是窗口的基本创建

//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);

同样在window proc中启用绘画,像这样

case WM_PAINT:
    m_pCanvas->Draw(m_pGraphics);
    break;

这样我在视觉上得到了我想要的东西

但他的方法的问题在于,整个窗口都可以点击,而仅使用 UpdateLayeredWindow 时,只有应该完全透明的部分才能像应有的那样点击。对于最后一种方法,我也有一种感觉,它更像是一种“hack”,而不是一种体面的方法。

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

【问题讨论】:

  • 这是一个 hack,您使用 GDI 以 24bpp 画笔和 0 的 alpha 绘制背景而使用 32bpp 和 255 的 alpha 绘制图像的意外。第二个方法是正确的。您需要为窗口提供与颜色键匹配的默认背景画笔。不是白色的,使用洋红色或石灰之类的东西。修复你的 WNDCLASSEX.hbrBackground
  • (HBRUSH)(COLOR_WINDOW+1); 更改wcex.hbrBackground = CreateSolidBrush( RGB(255, 255, 0) ); 实际上没有区别。我还更改了UpdateLayeredWindow中的颜色
  • UpdateLayeredWindow 期望位图具有预乘 alpha。这就是为什么您在第一个示例中得到不需要的白色边框的原因;预乘法会删除这个。
  • 你是对的,我已经预乘了 alpha,现在它就像一个魅力。

标签: c++ winapi gdi


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2010-10-07
    • 1970-01-01
    • 2014-09-12
    • 2017-02-15
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    相关资源
    最近更新 更多