【问题标题】:Win32 transparent controls on all versions ofWindows所有版本 Windows 上的 Win32 透明控件
【发布时间】:2011-05-24 18:04:19
【问题描述】:

我正在使用普通的 Win32 API(没有 MFC 或 .NET)开发一个 Win32 GUI 应用程序。我遇到的问题是使控件看起来透明。我想出了一种适用于大多数事情的方法,在 Windows Vista+ 中,我在 WndProc 中执行此操作:

case WM_CTLCOLORSTATIC:
{
    SetBkMode((HDC)wParam, TRANSPARENT);
    return (INT_PTR)::GetStockObject(NULL_PEN);
}
break;

在 Windows XP 中,我在 WndProc 中执行此操作:

case WM_CTLCOLORSTATIC:
{
    HBRUSH hbr = (HBRUSH)DefWindowProc(hDlg, message, wParam, lParam);
    ::DeleteObject(hbr);
    SetBkMode((HDC)wParam, TRANSPARENT);
    return (LRESULT)(HBRUSH)(COLOR_WINDOW);
}

现在这适用于大多数控件,但是我在组框控件顶部的标签上获得了透明背景,该控件通过文本绘制了组框线。我开始着手设计一个仅用于组合框的案例,但我确信这是一个以前必须解决的问题,我不想重新发明轮子。

是否有一种久经考验的方法可以使控件显示为透明?

谢谢, J

【问题讨论】:

  • 我认为你不应该那样删除画笔...
  • 您确定 alpha 通道在您想要的所有平台上都可用吗?那些必须在运行终端服务、远程桌面或 Windows Server 的 PC 上使用您的应用程序的人呢? “所有版本的 Windows”是什么意思?视窗 98?那也是Win32!如果这就是您的意思,也许您可​​以说“Windows XP 和更高版本的所有 Windows 版本”。
  • 您可能是对的,无论我是否删除画笔,它都有效。我不记得我从哪里得到那个代码了,但是有一个关于为什么画笔被这样删除的解释。
  • @Warren - 所有版本我的意思是 2000+,但我没有使用任何 alpha 通道,所以它们是否可用并不重要。
  • 您是否尝试过将画笔样式更改为透明(Clear)而不是删除它?我认为这样会更好。

标签: windows winapi user-interface


【解决方案1】:

要实现透明控制,您必须注意:

  • 你真的不能。标准的 windows 控件只是不支持“透明”绘画。
  • 即使你做对了,如果你调整它的大小,对话框也会严重闪烁。
  • 如果主题是打开或关闭,获得控件透明绘画工作的“技巧”往往会有所不同,并且会在 Windows 版本之间发生变化。

通常使控件“透明”的目的是使控件下的位图皮肤显示出来。实现这种透明度的方法是为控件的背景创建一个位图。然后使用位图中的CreatePatternBrush

这段 DialogProc 代码实现了最简单的蒙皮方法,然后负责绘制对话框的背景以及支持这种绘制形式的大多数控件:

  // _hwnd is the dialogs handle
  // _hbrSkin is a pattern brush handle
  HWND hwndCtl;
  POINT pt;
  HDC hdc;
case WM_CTLCOLORDLG:
  return (INT_PTR)_hbrSkin;
case WM_CTLCOLORSTATIC:
case WM_CTLCOLORBTN:
  hdc = (HDC)wParam;
  SetBkMode(hdc,TRANSPARENT); // Ensure that "static" text doesn't use a solid fill
  pt.x = 0; pt.y = 0;
  MapWindowPoints(hwndCtl,_hwnd,&pt,1);
  SetBrushOrgEx(hdc,-pt.x,-pt.y,NULL);
  return (INT_PTR)_hbrSkin;

重叠的控件将绘制不正确,因为其中一个会将其“透明”背景绘制在另一个之上。您可以通过以下方式减少闪烁:

  • 不允许调整对话框大小。
  • 在对话框上设置 WS_EX_COMPOSITED 样式,但由于 Windows NT 6 DWM 不支持它,从 Vista 开始它基本上没用。
  • 在对话框 & 或 WS_CLIPSIBLINGS 上设置 WS_CLIPCHILDREN 样式 - 这些样式会阻止使用组框和选项卡控件,因为它们依赖于控件重叠。
  • 对所有控件进行子类化,使用 WM_PRINTCLIENT 消息将它们绘制到后台缓冲区,然后在一次传递中对准备好的后台缓冲区进行 blitting。努力工作,并非所有控件都支持 WM_PRINTCLIENT。

【讨论】:

  • +1,出色的总结,包括 SetBrushOrgEx 调用,如果使用纯色背景进行测试,则很容易忽略。
  • 迟到了,但是想不通为什么SetBrushOrgEx中pt.x和pt.y的否定,如果0,0就是原点(bmp/brush的左上角对于窗口),并且 MapWindowPoints 返回编辑控件的窗口相对坐标,那么 pt.x 和 pt.y 应该按原样使用?
  • 为了获得透明的外观,子控件上使用的画笔与父控件上使用的画笔相同 - 其原点位于父控件的 0,0。因此,为了让所有子控件的背景与父控件对齐,它们必须将画笔重新设置为父控件的原点。
  • 感谢您的回答!当我禁用 SetBrushOrgEx 调用时,它的行为就好像子控件的画笔的原点已经在 BMP 上的 (0, 0) 处(至少我是这样认为的,作为窗口背景的左上角被绘制为孩子的背景 - 而不是孩子的预期背景)。这就是为什么它有点模糊,因为在我看来,我希望我必须朝积极的方向移动,以便设置从何处为子控件选择背景的位置(但它不是那样工作的,它真的需要否定的偏移量,这让我很困惑:)
猜你喜欢
  • 2020-12-14
  • 1970-01-01
  • 2014-06-19
  • 2012-03-27
  • 1970-01-01
  • 2018-09-25
  • 2016-02-15
  • 2023-03-29
  • 2011-11-12
相关资源
最近更新 更多