【问题标题】:Win32: How to make drop shadow honor non-rectangular Layered window?Win32:如何使阴影尊重非矩形分层窗口?
【发布时间】:2011-01-14 12:25:30
【问题描述】:

我通过添加 WS_EX_LAYERED 扩展样式创建了 layered window

wndClass.ExStyle = wndClass.ExStyle | WS_EX_LAYERED;

Windows 将使用黑色作为色度键颜色值。我将留下一个黑色的大边框以使问题变得明显:


窗口构建完成后,告诉use black as a chroma-key color

SetLayeredWindowAttributes(hwnd, 0x00000000, 255, LWA_COLORKEY);

现在弹出的分层窗口显示为部分透明:


问题是最后一步。我想使用自 Windows XP 起可用的 CS_DROPSHADOW 类样式来创建阴影:

wndClass.Style = wndClass.Style | CS_DROPSHADOW;

出现了投影,但是阴影包围了原来的矩形窗口,并没有考虑到分层窗口提供的窗口透明度:

有谁知道我在某个地方错过了什么神奇的选项,可以让投影尊重非矩形分层窗口?


出现此问题的另一个示例是当您不包含 6 像素填充/边距时。 Windows® 主题绘制的提示窗口是非矩形的。这会在窗口透明的地方留下一个小的可见间隙,但不会出现投影:

Microsoft 已设法使其工作,正如您从 Internet Explorer 的提示中看到的那样:


仔细查看 Windows tooltips 类提示窗口。使用 SpyXX - 我可以获得它的窗口矩形和类样式:

SpyXX 说:

Rectangle:     (440, 229)-(544, 249), 104x20
Restored Rect: (440, 229)-(544, 249), 104x20
Client Rect:   (0, 0)-(104, 20), 104x20

所以一切都指向窗口本身是 104x20 像素,在窗口本身之外有阴影。 (与CS_DROPSHADOW一致。)

接下来我可以看看tooltips窗口类的样式:

Windows Styles:     94000001

    WS_POPUP        80000000
    WS_VISIBLE      10000000
    WS_CLIPSIBLINGS  4000000
    TTS_ALWAYSTIP          1

Extended Styles:    00080088

    WS_EX_LAYERED      80000
    WS_EX_TOOLWIN         80
    WS_EX_TOPMOST          8

有趣的是,它没有使用CS_SAVEBITS (0x800);这对于小型、短暂的窗口很有用。

它也不使用CS_DROPSHADOW (0x20000)。所以现在我想知道它是如何在自己的窗口之外绘制的?

注意:透明分层窗口被记录为优于区域的技术。

编辑:分层 Windows 已随 Windows 2000 出现。CS_DropShadow 已随 XP 添加。

【问题讨论】:

  • 请让您的图片适合工作环境。
  • 我在一家银行工作,有时会进行电视直播采访,因此非常感谢编辑图像;否则我可能会失业。
  • 这是一个老问题,可能是错字,但你写了逻辑或(“||”),而应该按位或(“|”)写。

标签: winapi dropshadow layered-windows ws-ex-layered


【解决方案1】:

透明分层窗口被记录为优于区域的首选技术。

但是,CS_DROPSHADOW 确实关注区域。如果您使用区域裁剪或以其他方式塑造窗口,则投影将跟随新的轮廓。

幸运的是,您可以使用带有分层窗口的区域,并通过将两者结合起来获得您正在寻找的效果。

顺便说一句:tooltips_class32 确实使用 CS_DROPSHADOW - 您不会在窗口样式中看到它,因为它是类样式,而不是窗口样式。

【讨论】:

  • i 可以使用带有分层窗口的区域吗?由于两者都导致透明度,但(如您所说)只有区域会影响窗口的真实形状 - 有没有理由使用分层窗口? (如果是,那是什么?如果不是,为什么工具提示会使用它?)
  • 我会用工具提示窗口的窗口句柄四处寻找,看看我是否可以调用 GetWindowRgn 的等价物,看看它是否有一个。这应该回答了那部分,尽管不是为什么它首先是分层的。
  • 它们都可以用来给窗口一个可见的“形状”,但是它们做了非常非常不同的事情:区域有效地剪辑了窗口,完全排除了一些区域,而留下了剩下的东西一般;分层窗口仍然是矩形的,但被绘制成屏幕外位图并合成(有一个技巧可以让您继续使用普通的 WM_PAINT 绘图方法,但输出被重定向)。除了简单的颜色键透明度外,分层窗口还允许半透明甚至每像素的 Alpha 值(如果您直接处理绘图)。
  • @Ian:至于工具窗口,它们可能是为了性能而分层的。您注意到缺少CS_SAVEBITS - 这种样式对于分层窗口来说是不必要的,因为 Windows 必须绘制并保留它们下方的窗口才能在顶部合成分层窗口(如果非常大,这实际上会损害性能 使用了分层窗口,尽管如果 DWM 正在合成整个桌面,这可能不再是一个大问题)。
【解决方案2】:

为什么不使用 LWA_ALPHA 并将阴影构建到图像中?

编辑以回应您的评论:

A) 不会阻止您仅将 alpha 通道 PNG 用于阴影。将 2 张图像拼凑在一起并用作一张图像。
B) 生成阴影并不难。在图片中,您发布了具有 3 个不同 alpha 值的黑色。
C)但它不起作用,不是吗?即是时候发挥创意了。
D) 然后不要试图让 Windows 做一些它不会为你做的事情。
E) 完全不相关。分层窗口为您处理。

我强烈建议您了解有关分层窗口的更多信息,因为它们可以帮助您实现目标。

Edit2:你有位图。它相当容易扫描图像并找到哪些位将是彩色键控(通过自己识别黑色),然后将其修改为具有 0 的 alpha ,而其他所有内容的 alpha 为 255(不是:您可能必须转换将图像从较低颜色格式转换为 32 位图像,您可以通过创建新 DC 并复制图像来完成此操作)。这将为您提供与 LWA_ALPHA 和 LWA_COLORKEY 相同的效果。从那里很容易识别边缘的像素,颜色变为(R = 0,G = 0,B = 0,A = 0)。然后,您将第一个像素的 n alpha 更改为 192,一个将其设为 128,将其下方的一个设为 64。您现在在图像下方有一个看起来像阴影的 alpha'd 渐变。您可以调整 alpha 以获得您想要的效果。

【讨论】:

  • a) 我不控制图像;它来自当前启用的视觉主题 b)我没有生成方便的阴影的算法 c)Windows 已经提供了添加阴影的机制 d)我正在尝试使其成为视觉克隆Windows 做什么。 e) 对窗口后面的像素进行采样,以执行 alpha 混合,不仅可能不好(因为像素可以改变),而且是错误的 - 随着桌面组合的出现,并且会导致事情运行缓慢,因为合成器为我生成了一张桌面图片。
  • 为什么需要复制 Windows 的功能而不是使用已有的功能?
  • 因为它不能为所欲为。
  • 我应该为 alpha 通道 PNG 使用什么图像?在应用透明度后,我不知道窗口的形状或大小。而且,是的(c)它不起作用。这就是为什么我想我会问一个开发者社区,他们可能会看到我错过了什么。
【解决方案3】:

CS_DROPSHADOW 仅适用于标准矩形窗口。 WS_EX_LAYERED windows 不支持一切。它们更像是一种低级的自助服务方法,可以准确地绘制您想要的内容。

要获得投影,您必须自己从图像中的 Alpha 通道生成投影。

【讨论】:

  • 知道微软是如何在窗口外绘制阴影的吗?
  • +1,并接受答案。事实证明,微软不是使用分层窗口,而是使用区域来创建大小合适的投影。在工具提示 hWnd 上调用 GetWindowRgn 返回圆角矩形区域。所以 CS_DropShadow 不支持分层窗口。
猜你喜欢
  • 2011-05-13
  • 2012-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多