65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.07/5 (12投票s)

2005年8月12日

5分钟阅读

viewsIcon

75170

downloadIcon

800

一个支持同步和异步渐变,以及FadeOnLoad、FadeOnClose和FadeOnHover选项的窗体渐变器。

引言

这个项目的目标不是开发另一个窗体渐变器,而是整合其他窗体渐变器的独特功能,并可能加以改进。大多数其他窗体渐变器的一个主要限制是缺乏定制性。许多渐变器拥有包含按需渐变等功能的代码,但只提供加载和关闭时的渐变。

我们决定本项目的目标功能应包括:

  1. 同步和异步渐变。
  2. 鼠标悬停时全不透明。
  3. 能够用另一个渐变中断渐变。

使用代码

使用这个窗体渐变器与其他大多数用法无异。窗体渐变器的功能包含在FormFader.FormFader类中。要使用渐变器,只需添加对FormFader库的引用,并继承自FormFader.FormFader

FormFader有几个相关的属性:

  • CurrentFade - 获取窗体的状态:FadeInFadeOutNotFading
  • 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()调用的堆叠将导致严重的性能问题和潜在的溢出,从而导致随机崩溃。

工作原理

负责渐变窗体的大部分代码由单个TimerTick事件处理。使用Timer而不是循环(就像许多其他窗体渐变器一样)有几个好处:

  1. Timer在不同的线程上运行。
  2. 可以控制渐变的速率或FadeRate
  3. Timer可以被停止。

渐变器的大部分代码最好通过查看完整的源代码来理解。但是,有一个方面我想详细说明,那就是FullOpacityOnHover属性。更具体地说,检测鼠标是否悬停在窗体上的能力。

尽管WinForms提供了MouseEnterMouseLeave事件,但它们仅限于指定的控件。将鼠标移到窗体的子控件上会触发窗体的MouseLave事件和子控件的MouseEnter事件。为了确定鼠标何时在窗体的任何部分内,开发了一个名为MouseBounds的消息过滤器。

对于每个FormFader,都会添加一个新的MouseBounds过滤器实例。添加后,每次鼠标离开或进入窗体时,都会触发自定义事件MouseBounds.MouseBoundsChangedMouseBounds.MouseInBoundsbool属性决定了鼠标是否在窗体边界内。

通过使用过滤器监听WM_NCMOUSEMOVEWM_MOUSEMOVEWM_NCMOUSELEAVEWM_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版本。
© . All rights reserved.