winapi - 如何正确使用 LayeredWindows

Posted

技术标签:

【中文标题】winapi - 如何正确使用 LayeredWindows【英文标题】:winapi - How to use LayeredWindows properly 【发布时间】:2012-05-04 09:51:54 【问题描述】:

我无法理解 UpdateLayaredWindow api 的概念、它的工作原理以及如何实现它。例如,我想覆盖 CFrameWnd 并使用 UpdateLayeredWindow 绘制一个自定义的 alpha 混合框架,据我了解,绘制子控件的唯一方法是:将它们混合到框架的位图缓冲区(使用 CreateCompatibleBitmap 创建)并重绘整个框架,或者创建另一个位于分层框架顶部并定期绘制子控件的窗口(这违背了分层窗口的整个想法,因为窗口区域无论如何都不会更新)。

如果我使用第一种方法,整个框架会被重绘——这对于大型应用程序来说肯定是不切实际的..?还是帧总是不断更新,所以修改位图缓冲区不会导致额外的重绘。

一个类似于我想要实现的窗口示例是 Skype 通知框/来电框。一个半透明的框架/窗口,顶部有子控件,您可以在屏幕上移动。

在实际的商业世界中,我该怎么做?请不要让我参考文档,我知道它在说什么;我需要有人解释我应该用来实现它的基础设施的实用方法。

谢谢。

【问题讨论】:

在实际的商业世界中,您永远不会重新实现标准窗框。这是完全没有意义的,并且会大大增加您在实现中出现错误的可能性。 我没有重新实现它的功能,我只是根据我得到的设计绘制一个自定义框架。在实际的商业世界中,如果我无法在设计方面交付客户想要的东西,我就不会得到报酬 【参考方案1】:

目前还不清楚分层窗口的哪些方面会给您带来问题,我将简单介绍一下它们是如何实现的,并从中解释它们的局限性。

分层窗口是通过使用称为“层”的视频适配器的硬件功能实现的。适配器具有组合来自不同视频内存块的像素的基本能力,在将它们发送到监视器之前将它们混合。明显的例子是鼠标光标,它被叠加在桌面帧缓冲区的像素上,因此当您移动鼠标时不需要花费太多精力来为其设置动画。或者用于显示视频的叠加层,视频流解码器将视频像素直接写入单独的帧缓冲区。或者顶层窗口的框架投射在它后面的窗口之上的阴影。

视频适配器允许在组合两个像素值时对它们进行一些简单的逻辑操作。第一个是显而易见的,即让一些像素值与背景像素重叠的混合操作。该效果提供不透明度,您可以在窗口后面看到部分背景。

第二个是颜色键控,当电视上的气象员站在气象图前时,您会看到这种效果。他实际上站在一个绿色屏幕前,摄像机混合面板过滤掉绿色并用天气地图中的像素替换它。这种效果提供了纯粹的透明度

您可以在传递给 UpdateLayeredWindow() 的参数中看到这一点,您必须在代码中调用该函数来设置分层窗口。 dwFlags 参数选择视频硬件支持的基本操作,ULW_ALPHA 标志启用不透明效果,ULW_COLORKEY 标志启用透明效果。透明效果需要使用 crKey 参数值指定的颜色键。不透明度效果由 pblend 参数控制。这是为未来的扩展而构建的,尚未发生。 BLENDFUNCTION 结构中唯一有趣的字段是 SourceConstantAlpha,它控制不透明度。

因此,可用于分层窗口的基本效果是不透明度,与背景窗口重叠并保持部分可见。对整个窗口的一个限制是部分不透明,包括边框和标题栏。这看起来不太好,您通常希望创建一个无边框窗口并承担创建自己的窗口框架的负担。顺便说一句,需要一堆代码。

基本效果是透明,完全隐藏窗口的一部分。您经常希望结合这两种效果,这需要两个分层窗口。一个提供部分不透明度,另一个在顶部并由底部拥有,它显示不透明的窗口部分,如控件。使用颜色键使其背景透明并使底部窗口可见。

除此之外,自定义窗口的另一个重要功能是由 SetWindowRgn() 启用的。它可以让你给窗口一个矩形以外的形状。同样重要的是省略边框和标题栏,它们不适用于形状窗口。编程工作是以一种与其他应用程序创建的窗口的外观没有太大区别的雅致方式组合这些功能,并编写代码来绘制替换窗口部件并仍然使窗口功能像一个常规窗口。例如,调整窗口大小和移动窗口之类的事情,您通常通过自定义处理 WM_NCHITTEST 消息来实现。

【讨论】:

谢谢!我知道我的问题有点杂乱无章:P 对 LayeredWindows 背后的东西的很好的解释。您能否解释一下您将如何使用 UpdateLayeredWindow 函数以及如何以有效的方式实现子控件?:) 如果这个答案不足以解释如何使用 UpdateLayeredWindow() ,那么我无法为您提供进一步的帮助。 “以有效的方式实施子控件”与问题没有任何关系,并且方式不具体。 我知道如何在基本层面上使用它,但我只是不明白如何构建我的应用程序以使其与子控件等一起使用。

以上是关于winapi - 如何正确使用 LayeredWindows的主要内容,如果未能解决你的问题,请参考以下文章

在WINAPI中做透明按钮的正确方法

GetScaleFactorForMonitor winapi 是不是返回不正确的比例因子?

使用winapi进行远程程序控制[关闭]

无法加载多个位图 - WinAPI [重复]

WinAPI 的 Groupbox 字体问题

如何更改静态文本控件(winapi)的字体?