Janky_H
contact me at Janky_H@hotmail.com
原文:https://msdn.microsoft.com/en-us/library/ms997507.aspx
Layered Windows
Windows 2000 introduces a new extended window style bit: WS_EX_LAYERED. When used properly, it can significantly improve performance and visual effects for a window that has a complex shape, animates, or wishes to use alpha-blending effects.
windows 2000引入了新的窗口扩展风格,其标识位为WS_EX_LAYERED.合理使用该风格即可显著改善那些拥有复杂形状、繁杂绘制或者希望拥有混合透明效果的窗口性能及其视觉效果。
Windows appear as rectangles on the screen clipped by other windows. For a window in an application to look like a circle, it's not enough for the application to simply paint a window as a circle; the system will continue to hit test this window as a rectangle and windows underneath this window will still be clipped by the window's rectangle. So, the window will look and behave like a gray rectangle with a circle in the middle.
Some applications might take a snapshot of the visual bits underneath the window before it was actually shown and later compose those bits with the window bits. This approach doesn't quite work in a multiprocess, multitasking environment, because other windows can paint underneath this window. The application has no way of knowing when such painting occurs or how to somehow retrieve the newly painted bits underneath.
窗口以矩形的形式出现在屏幕上,并且被其它窗口所裁剪。例如应用程序中一个圆形的窗口,仅仅依靠程序将其绘制为一个圆形是不够的;系统仍然通过点击测试将其视为一个矩形,其下的窗口也仍然被这个矩形所裁剪。所以该窗口看似为圆形,但依然拥有矩形窗口的行为。
一些应用程序会采取在显示自身窗口之前以快照的形式,记录下自身窗口下其余窗口的可视区域位,然后将记录下的这些位与自身进行组合的方式,以实现透明。然而该方式在多进程、多任务的环境中却并不能很好工作,因为其余的窗口会绘制该窗口之下的窗口部分。应用程序自身不能获知该种绘制行为何时会发生,也不能够取得那些最新的绘制信息。
译者注:这里原文中的例子表述不够形象,在此我更加白话描述一下吧。
假设我们要做一个时钟应用程序,时钟是圆形的,我们自然是用一个windows窗口予以实现。然而请注意一下几点:
1. windows中的每个窗口都是一个矩形,可以通过下面将要提到的窗口区域改变其形状,但我们这里保持窗口的矩形状态。
2. 我们要用矩形的窗口实现圆形的时钟窗口,怎么办呢?我将之称为视觉虚拟方法。具体做法如下:
a. 在矩形窗口中央绘制一个圆形,作为时钟形状。
b. 将时钟圆形面之外的所有矩形区域设置为透明。这样用户看到的就只有窗口的圆形区域,这样就实现了时钟的效果。但请记住我们的窗口仍然是矩形。接下来就是如何设置透明了,原文描述采用的是这样的方式:设法获得我们矩形窗口之下,其余窗口与我们窗口重合区域的颜色信息,然后将这些信息绘制到我们窗口的非时钟圆的其余区域。说白了就是把下面窗口的样子画到我们自己窗口上,给人的错觉就是自己的窗口透明了—看到了下面窗口的样子。---DONE
In Windows 95/98 and Windows NT® 4.0 the proper way for an application to create a window with a complex shape, such as a rounded balloon or a cool transparent digital clock, is to specify the shape by supplying the window region representing the shape via the SetWindowRgn API. There are several drawbacks to using window regions. If a regional window animates its shape frequently or is dragged on the screen, Windows will have to ask windows beneath the regional window to repaint. Besides generating more message traffic, the calculations that occur when Windows tries to figure out invalid regions or visible regions become increasingly expensive when a window has an associated region. In addition, using window regions only addresses transparency—that is, color-key effects. It does not address translucency—that is, a way to top-level windows.
在windows95/98 和windows NT 4.0中,应用程序要创建一个具有复杂形状窗口(例如圆形的气球状、透明的数字时钟)的一般方法,是通过调用SetWindowRgn并为其提供描绘窗口形状的窗口区域参数。然而,使用窗口区域是带有一些缺陷的:如果一个窗口反复的绘制自己或被频繁地在屏幕上拖曳,windows就会要求该窗口之下的其余窗口重绘自己。其结果除了因大量消息而导致的拥堵外,也将使windows因为反复地计算窗口无效区域和可视区域,而浪费昂贵的资源与时间。此外使用窗口区域只能处理窗口透明而不能处理半透明的效果。
译者注:
1. 例如我们要创建一个椭圆形的窗口,在MFC中的实现方法是:
- CRect rect;
- GetWindowRect(&rect);
- this->ScreenToClient(&rect);
- CRgn region;
- region.CreateEllipticRgn(rect.left, rect.top, rect.right, rect.bottom);
- SetWindowRgn((HRGN)region.GetSafeHandle(), TRUE);
2. 窗口透明与半透明的区别:
窗口透明: 针对某一特定颜色。透过该颜色的区域可以看到下层窗口,并且该区域不捕获鼠标消息,
点击这些区域会使下层窗口获得捕获鼠标,而使其获得输入焦点。
窗口半透明:针对整个窗口。透过整个窗口都可以看见下层窗口,当alpha值不为0时,该窗口能捕
所有自身的鼠标点击消息。当alpha值为0时,所有鼠标点击消息都被下层窗口拥有。
This is where layered windows come to the rescue. Layered windows really encompass two different concepts: layering—windows' ability to exhibit sprite-like behavior; and redirection—the system's ability to redirect the drawing of legacy windows into an off-screen buffer.
这便是分层窗口发挥作用的地方。分层窗口包含了两个概念:分层---窗口展示自己幽灵般行为的能力(半透明);重定向---系统将原有窗口的绘制重定向到一个离屏缓冲区的能力。
Using a layered window can significantly improve performance and visual effects for a window that has a complex shape, animates its shape, or wishes to use alpha blending effects. The system automatically composes and repaints layered windows and the windows of underlying applications. As a result, layered windows are rendered smoothly, without the flickering typical of complex window regions. In addition, layered windows can be partially translucent, that is, alpha-blended.
使用分层窗口可以显著提高那些拥有复杂形状、或希望使用alpha混合效果的窗口性能及其视觉外观。系统会自动组合并重绘分层的窗口和其下的其余窗口。最终分层窗口会被平滑地绘制,而不会出现闪烁。此外,分层窗口还可以拥有alpha混合效果,即半透明效果。
Using Layered Windows使用分层窗口
For any layering to take place, the WS_EX_LAYERED bit needs to be set, either at window creation time or by callingSetWindowLong with GWL_EXSTYLE. Next, the developer has a choice: Use the existing Microsoft Win32® painting paradigm by responding to WM_PAINT and/or other paint messages, or make use of a more powerful layering API,UpdateLayeredWindow.
To use UpdateLayeredWindow, the visual bits for a layered window have to be rendered into a compatible bitmap. Then, via a compatible GDI Device Context, the bitmap is provided to the UpdateLayeredWindow API, along with the desired color-key and alpha-blend information. The bitmap can also contain per-pixel alpha information.
Note that when using UpdateLayeredWindow the application doesn't need to respond to WM_PAINT or other painting messages, because it has already provided the visual representation for the window and the system will take care of storing that image, composing it, and rendering it on the screen. UpdateLayeredWindow is quite powerful, but it often requires modifying the way an existing Win32 application draws.
为了对top-level窗口进行分层,必须为窗口添加WS_EX_LAYERRED扩展风格标志位,方法之一是在窗口创建时调用SetWindowLong为其指定GWL_EXSTYLE参数。接下来程序员可以选择使用传统绘制模式,响应WM_PAINT等绘制消息,或者可以调用更加强大的分层函数UpdateLayeredWindow.
使用UpdateLayeredWindow,分层窗口内的可视信息必须被绘制到一幅兼容位图,然后通过兼容GDI设备上下文,将该位图连同期望的色键值和alpha-blend(透明混合)信息传递给UpdateLayeredWindow。同时位图还可以包含单个像素的alpha信息。
请注意当使用UpdateLayeredWindow时,应用程序并不需要相应WM_PAINT等绘制消息,因为它已经提供了描述窗口可视化的信息,然后系统会负责处理保存图片、组合图片并将其绘制到屏幕。UpdateLayeredWindow相当强大,但它却时常要求修改一个win32应用程序的绘制方式。
The second way to use layered windows is to continue using the Win32 painting paradigm, but allowing the system to redirect all the drawing for the layered window and its children into an off-screen bitmap. This can be done by callingSetLayeredWindowAttributes with the desired constant alpha value and/or the color-key. Once the API has been called, the system will start redirecting all drawing by the window and automatically apply the specified effects.
To set the opacity level or the transparency color key for a given layered window, callSetLayeredWindowAttributes.After the call, the system may still ask the window to paint when the window is shown or resized. However, because the system stores the image of a layered window, the system will not ask the window to paint if parts of it are revealed as a result of relative window moves on the desktop. Legacy applications do not need to restructure their painting code if they want to add translucency or transparency effects for a window, because the system redirects the painting of windows that called SetLayeredWindowAttributes into off-screen memory and recomposes it to achieve the desired effect.
使用分层窗口的第二种方式,是遵循win32的绘制模式,但允许系统将分层窗口连同其子窗口的所有绘制操作,重定向到一幅off-screen位图中。其实现方法是调用SetLayeredWindowAttributes函数,并指定期望的alpha常量值,也可同时指定色键值。一旦调用了该API,系统便开始进行绘制重定向实现指定的效果。
为了设置分层窗口的不透明度,或者其透明色键值,调用SetLayeredWindowAttributes函数。之后,当该窗口需要显示或其大小改变时,系统仍然会要求其自身进行重绘。然而,由于系统存储了分层窗口镜像,当窗口本身因为桌面其余窗口的移动而使自身视区改变时,系统并不会要求窗口绘制自己。原有应用程序并不需要重新组织自身的绘制代码结构,以实现透明效果,因为系统会将那些调用SetLayeredWindowAttributes的窗口的绘制,重定向到一块离屏内存区域,然后重新组合窗口以获得期望效果。
Using UpdateLayeredWindow attributes may be more efficient at times, because the application may not need to store a memory bitmap for every layered window. The application can keep one memory bitmap and render into it just before calling UpdateLayeredWindow for a number of layered windows. Depending on how often the application calls UpdateLayeredWindow, it can also delete the bitmap after calling the API. On the other hand, windows redirected by the system will always carry the overhead of having to maintain a memory bitmap for every redirected window. This is in addition to the memory normally consumed by a layered window if UpdateLayeredWindow was used to display it. Thus, while certainly more convenient, using SetLayeredWindowAttributes comes with a price tag. If your window does a fast animation, UpdateLayeredWindow is the way to go.
通常使用UpdateLayeredWindow会更加高效,因为使用这种方式应用程序无需为每一个分层窗口都存储一张位图,而只需保存一张位图,并在调用UpdateLayeredWindow之前对其进行填充绘制。根据应用程序调用UpdateLayeredWindow的频率,可以选择在调用该API之后删除位图。另一方面,使用SetLayeredWindowAttributes模式时,总是要求系统为每一个被重定向的窗口都维护一块位图内存区域。
且这些内存区域并不包括使用UpdateLayeredWindow显示窗口所需要的内存空间。因此,如果你的窗口需要快速的绘制,UpdateLayeredWindow才是最好的选择。
Please remember that once SetLayeredWindowAttributes has been called on a layered window, subsequentUpdateLayeredWindow calls will fail until the layering style bit is cleared and set again. This is becauseSetLayeredWindowAttributes turns on the redirection of the window's drawing, and once that happensUpdateLayeredWindow can give contradictory information as to what the window really looks like.
请注意一旦为分层窗口调用了SetLayeredWindowAttributes,之后的UpdateLayeredWindow调用将失败,直到分层窗口样式标识位WS_EX_LAYERED被清除,然后被重新设置。因为分层窗口的重定向行为因SetLayeredWindowAttributes而开始,但UpdateLayeredWindow却提供了关于窗口形状的相反信息。
Hit Testing点击测试(命中测试)
Hit testing of a layered window is based on the shape and transparency of the window. This means that the areas of the window that are color-keyed or whose alpha value is zero will let the mouse messages through.
分层窗口的点击测试,是基于窗口形状及其透明效果的。这意味着窗口中那些被设置为透明(color-key属性或alpha值为0)的区域,忽略鼠标点击消息而使其被下面的窗口捕获。
If the layered window has the WS_EX_TRANSPARENT extended window style, the shape of the layered window will be ignored and the mouse events will be passed to the other windows underneath the layered window.
如果一个分层窗口含有WS_EX_TRANSPARENT扩展风格,那么窗口形状将被忽略,鼠标事件会被传递给该窗口之下的其他窗口。
Transition Effects 过渡效果
You don't need to write a lot of code to fade a window in or out. The AnimateWindow API can do all the work for you. In fact, this is how the shell's Start menu and other menus do the open fade-in effect.
你不必编写许多代码去实现窗口的淡入或淡出效果。AnimateWindow函数将为你提供所有支持。实际上这便是shell中开始按钮或其它菜单淡入效果的实现方式。
Internally, AnimateWindow will make your windows layered and give the desired transition effect.
Besides fades, AnimateWindow can also do sliding effects. In fact, if you're writing custom menus, this API can be quite useful. To be a good desktop citizen, your application should figure out whether, when showing the menu, to animate it at all. To get that information, you should query the system via the SystemParametersInfo API using SPI_GETMENUANIMATION. Furthermore, you can use SPI_GETMENUFADE to determine whether to use the slide or the fade
animation effect. Once you know what effect to use, pass in AW_SLIDE to AnimateWindow to get the slide effect and AW_BLEND to get the fade effect.
AnimateWindow also has a parameter that specifies how long the transition should take. Typically, a transition effect shouldn't take longer than 200 milliseconds.
在内部,AnimateWindow会分层你的窗口,并赋予其过渡的效果。
除了淡化效果,AnimateWindow还能实现滑动效果(幻灯片效果)。当你创建一个自定义菜单时,该函数将会大有用处。要作为桌面上良好的一员,你的应用程序就应该知道何时去绘制,激活自己的菜单。为了获得这些信息,你得通过向SystemParametersInfo传递SPI_GETMENUANIMATION标识,以询问系统。然后你可以使用SPI_GETMENUFADE来决定是否使用淡化或滑动效果。在决定了该使用的效果之后,你就可以向
AnimateWindow传递AW_SLIDE以指定滑动效果,或者AW_BLEND指定淡化效果。
AnimateWindow还有一个用于指定过渡时间的参数。通常,一次过渡效果不应超过200毫秒。
Examples of Using Layered Windows(使用分层窗口示例)
If you want a dialog box to come up as a translucent window:
为对话框指定半透明效果:
1. Create the dialog box as usual.
2. On WM_INITDIALOG, set the layered bit of the window's extended style and callSetLayeredWindowAttributes with the desired alpha value.
The code might look like this:
// Set WS_EX_LAYERED on this window
SetWindowLong(hwnd, GWL_EXSTYLE,GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// Make this window 70% alpha
SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);
转自:http://blog.csdn.net/JankyHu/article/details/5936401