不仅仅是另一个窗体淡入淡出






4.07/5 (12投票s)
2005年8月12日
5分钟阅读

75170

800
一个支持同步和异步渐变,以及FadeOnLoad、FadeOnClose和FadeOnHover选项的窗体渐变器。
引言
这个项目的目标不是开发另一个窗体渐变器,而是整合其他窗体渐变器的独特功能,并可能加以改进。大多数其他窗体渐变器的一个主要限制是缺乏定制性。许多渐变器拥有包含按需渐变等功能的代码,但只提供加载和关闭时的渐变。
我们决定本项目的目标功能应包括:
- 同步和异步渐变。
- 鼠标悬停时全不透明。
- 能够用另一个渐变中断渐变。
使用代码
使用这个窗体渐变器与其他大多数用法无异。窗体渐变器的功能包含在FormFader.FormFader
类中。要使用渐变器,只需添加对FormFader库的引用,并继承自FormFader.FormFader
。
FormFader
有几个相关的属性:
CurrentFade
- 获取窗体的状态:FadeIn
、FadeOut
或NotFading
。FadeAmount
- 获取/设置每次渐变迭代之间的增量值。FadeRate
- 获取/设置(以毫秒为单位)每次渐变迭代之间的时间。FadeOnLoad
- 获取/设置一个值,用于确定在加载时是否应从0透明度同步渐变到FadeOapcity
。FodeOnClose
- 获取/设置一个值,用于确定在关闭时是否应从当前Opacity
同步渐变到0。FadeOpacity
- 获取/设置窗体应渐变到的值。FullOpacityOnHover
- 获取/设置一个值,用于确定将鼠标悬停在窗体上是否应强制异步渐变到100%。
同步和异步渐变
渐变窗体很简单。首先,需要设置FadeOpacity
属性。然后,简单的调用方法即可确定窗体是同步渐变还是异步渐变。
异步渐变如下所示:
this.FadeOpacity = .75;
this.Fade();
同步渐变如下所示:
this.FadeOpacity = .75;
this.FadeAndWait();
鼠标悬停时全不透明
将此值设置为true
将在鼠标位于窗体边界内(包括非客户端区域)时强制异步渐变到100%。当鼠标移出边界时,窗体会渐变回FadeOpacity
的当前值。
能够用另一个渐变中断渐变
如果一个渐变已启动并且正在处理中(CurrentFade != NotFading
),并且再次调用Fade()
,则第一个渐变会被停止,第二个渐变将优先执行。这很重要的一点是,当FullOpacityOnHover
设置为true
时,可以实现快速响应。如果没有能力中断当前渐变,一系列Fade()
调用的堆叠将导致严重的性能问题和潜在的溢出,从而导致随机崩溃。
工作原理
负责渐变窗体的大部分代码由单个Timer
的Tick
事件处理。使用Timer
而不是循环(就像许多其他窗体渐变器一样)有几个好处:
Timer
在不同的线程上运行。- 可以控制渐变的速率或
FadeRate
。 Timer
可以被停止。
渐变器的大部分代码最好通过查看完整的源代码来理解。但是,有一个方面我想详细说明,那就是FullOpacityOnHover
属性。更具体地说,检测鼠标是否悬停在窗体上的能力。
尽管WinForms提供了MouseEnter
和MouseLeave
事件,但它们仅限于指定的控件。将鼠标移到窗体的子控件上会触发窗体的MouseLave
事件和子控件的MouseEnter
事件。为了确定鼠标何时在窗体的任何部分内,开发了一个名为MouseBounds
的消息过滤器。
对于每个FormFader
,都会添加一个新的MouseBounds
过滤器实例。添加后,每次鼠标离开或进入窗体时,都会触发自定义事件MouseBounds.MouseBoundsChanged
。MouseBounds.MouseInBounds
的bool
属性决定了鼠标是否在窗体边界内。
通过使用过滤器监听WM_NCMOUSEMOVE
、WM_MOUSEMOVE
、WM_NCMOUSELEAVE
和WM_MOUSELEAVE
消息,然后检查鼠标位置
_mouseInBounds = formFader.Bounds.Contains(Cursor.Position)
以高水平的性能,可以确定鼠标是在窗体边界内还是边界外。
避免闪烁
避免大部分闪烁的快捷方式是使用透明键。选择一个不会影响程序的颜色,例如亮绿色,或其他一些不被窗体上任何东西使用的难看颜色。
窗体有时会闪烁的原因,通常与WinForms处理透明窗口的bug有关。WinForms实际上只是Windows API的包装器。在处理透明度时,WinForms将使用Windows API将您的窗体转换为所谓的“分层窗口”。
“使用分层窗口可以显著提高具有复杂形状、动画形状或希望使用Alpha混合效果的窗口的性能和视觉效果。” – MSDN
但是,WinForms不会在认为有必要之前将窗口变成分层窗口。您看到的闪烁是WinForms试图将非分层窗口转换为分层窗口。
设置透明键有效的原因是,WinForms会强制任何带有透明键的窗口成为分层类型。在设计时设置透明键,在运行时,窗口将始终是分层窗口。由于无需转换,因此闪烁消失了。
关注点
正如在示例项目中所示,您可以将事件处理程序附加到几个指示属性更改的事件上。
历史
- 2005年8月12日 - 发布1.0版本。