Click here to Skip to main content
15,887,027 members
Articles / Multimedia / GDI+
Article

Fading Forms In and Out

Rate me:
Please Sign up or sign in to vote.
4.17/5 (15 votes)
13 Aug 2007CPOL2 min read 106.9K   1.3K   85   35
Add fade transitions to your applications
Screenshot - FadeForm.jpg

Introduction

Disclaimer: I am not the first to make a form fader, but I couldn't find one that did exactly what I wanted and so I created this.

I have had need in the past to cause my forms to perform fade transitions from one opacity to another. It was usually on load, close and window state changes. I finally decided to bring it all together in a nice, extendable Form. The FadeForm...

  • fades in on open.
  • fades out on close.
  • partially fades out on focus lost.
  • fades in on focus.
  • fades out on minimize.
  • fades in on restore.
  • must not annoy the user. :-) A form fader definitely has that potential.

Using the Code

To use FadeForm, just extend it instead of Form and you are ready to go.

C#
public class Form1 : FadeForm
{
     ...
}

It is defaulted to use the fade-in from nothing on open and out to nothing on close. It will also fade to 85% opacity when not the active window. You can set it to whatever you want, however.

C#
//This would set the form with its default values.
this.ActiveOpacity=1;
this.InactiveOpacity=.85;
this.MinimizedOpacity=0;

You may, from time to time, want to disable the fade effect.

C#
this.DisableFade(); //Turn off fade effects
this.EnableFadeDefaults(); //Turns on fade effects

You can also change the transition time.

C#
this.FadeTime=1; //1 sec transition

You can also do a one-time fade to any value.

C#
this.TargetOpacity=.25; //Fades the form to 25% opacity

Points of Interest

The opening and focus change events were easy to deal with. It was appropriate to use the built-in event listeners.

C#
public FadeForm()
{
    ...
    this.timer.Tick += new System.EventHandler(this.timer_Tick);
    
    this.Deactivate += new System.EventHandler(this.FadeForm_Deactivate);
    this.Activated += new System.EventHandler(this.FadeForm_Activated);
    this.Load += new System.EventHandler(this.FadeForm_Load);
}

private void FadeForm_Load(object sender, EventArgs e)
{
   this.Opacity = minimizedOpacity;
   this.TargetOpacity = activeOpacity;
}

private void FadeForm_Deactivate(object sender, EventArgs e)
{
    this.TargetOpacity = inactiveOpacity;
}

private void FadeForm_Activated(object sender, EventArgs e)
{
    this.TargetOpacity = activeOpacity;
}

The minimize and close events where a little trickier because the actions had to be postponed until the fade transition was complete. I had to override WndProc in order to catch the request for those actions and postpone the action until the transition was done.

C#
private const int WM_SYSCOMMAND = 0x112;
private const int WM_COMMAND = 0x111;
private const int SC_MINIMIZE = 0xF020;
private const int SC_RESTORE = 0xF120;
private const int SC_CLOSE = 0xF060; 

// Intercepts WindowMessages before they are processed.
protected override void WndProc(ref Message m)
{
    if (m.Msg==WM_SYSCOMMAND||m.Msg == WM_COMMAND) 
    {
        //Fade to zero on minimze
        if (m.WParam == (IntPtr)SC_MINIMIZE) 
        { 
            heldMessage = m;
            this.TargetOpacity = minimizedOpacity;
            return;
         }

         //Fade in if the window is restored from the taskbar
         else if (m.WParam == (IntPtr)SC_RESTORE 
           && this.WindowState == FormWindowState.Minimized) 
         { 
             base.WndProc(ref m);  
             this.TargetOpacity = activeOpacity;
             return;
         }

         //Fade out if the window is closed.
         else if (m.WParam == (IntPtr)SC_CLOSE) 
         { 
             heldMessage = m; 
             this.TargetOpacity = minimizedOpacity;
             return;
         }
     }
     base.WndProc(ref m);
}

Once that was done, all I had to do was perform the transitions.

C#
//Performs fade increment.
private void timer_Tick(object sender, EventArgs e)
{
    double fadeChangePerTick = timer.Interval * 1.0 / 1000 / fadeTime;

    //Check to see if it is time to stop the timer
    if (Math.Abs(targetOpacity - this.Opacity) < fadeChangePerTick)
    {
        //There is an ugly black flash if you set the Opacity to 1.0
        if (targetOpacity == 1) this.Opacity = .999;
        else this.Opacity = targetOpacity;
        
        //Process held Windows Message.
        base.WndProc(ref heldMessage);
        heldMessage = new Message();
        
        //Stop the timer to save processor.
        timer.Stop();
    }
    else if (targetOpacity > this.Opacity) this.Opacity += fadeChangePerTick;
    else if (targetOpacity < this.Opacity) this.Opacity -= fadeChangePerTick;
}

It is interesting to notice that the opacity is never actually 1. That was a hack on my part to keep the window from flashing black. I am not sure what the cause of this is, but the fix was easy, so I may never know.

You can see that I stop the timer after I reach my target opacity. You may wonder how it gets started. Every time I set TargetOpacity, the set method starts the timer. There's no sense running the timer and wasting processor power when you don't need it.

C#
private double TargetOpacity
{
    set
    {
        targetOpacity = value;
         if (!timer.Enabled) timer.Start();
    }
    get 
    { 
        return targetOpacity; 
    }
}

I think I made it about as easy as possible. I always like to adhere to the KISS principle: Keep it simple, stupid.

Thoughts

I plan to add a Notify(int n) method that will oscillate the opacity n times in order to get the user's attention. I also think it would be nice to give a choice between mouseover-based and focus-based transitions.

History

  • 13 August, 2007 -- Original version posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Instructor / Trainer
United States United States
I am a mechanical engineer that works as a high school math teacher in Mulberry, Arkansas. I use programming as one way to keep my mind sharp.

Comments and Discussions

 
Generalblack flash Pin
roundy7215-Mar-09 9:23
roundy7215-Mar-09 9:23 
GeneralRe: black flash Pin
Nicholas Seward15-Mar-09 15:49
Nicholas Seward15-Mar-09 15:49 
GeneralRe: black flash Pin
Atanas Palavrov1-Apr-09 16:37
Atanas Palavrov1-Apr-09 16:37 
GeneralRe: black flash Pin
Atanas Palavrov12-May-09 9:14
Atanas Palavrov12-May-09 9:14 
GeneralRe: black flash [modified] Pin
Nicholas Seward12-May-09 10:13
Nicholas Seward12-May-09 10:13 
GeneralRe: black flash Pin
Atanas Palavrov14-May-09 3:54
Atanas Palavrov14-May-09 3:54 
GeneralRe: black flash Pin
Nicholas Seward14-May-09 5:49
Nicholas Seward14-May-09 5:49 
GeneralSystem ERROR Occured in Application Pin
coolpul6-Sep-08 2:50
coolpul6-Sep-08 2:50 
General.999 opacity and layout execution time Pin
nukefusion26-Nov-07 4:10
nukefusion26-Nov-07 4:10 
GeneralGeneral Comments Pin
Christopher Stratmann22-Aug-07 2:25
Christopher Stratmann22-Aug-07 2:25 
GeneralRe: General Comments Pin
Nicholas Seward26-Aug-07 7:05
Nicholas Seward26-Aug-07 7:05 
GeneralRe: General Comments Pin
Christopher Stratmann27-Aug-07 1:13
Christopher Stratmann27-Aug-07 1:13 
GeneralRe: General Comments Pin
Nicholas Seward27-Aug-07 4:46
Nicholas Seward27-Aug-07 4:46 
GeneralRe: General Comments Pin
Christopher Stratmann27-Aug-07 8:44
Christopher Stratmann27-Aug-07 8:44 
GeneralRe: General Comments Pin
Nicholas Seward27-Aug-07 10:25
Nicholas Seward27-Aug-07 10:25 
GeneralRe: General Comments Pin
Christopher Stratmann27-Aug-07 8:54
Christopher Stratmann27-Aug-07 8:54 
QuestionDoes it work with VB .Net ? Pin
Patrice Dargenton22-Aug-07 0:26
Patrice Dargenton22-Aug-07 0:26 
AnswerRe: Does it work with VB .Net ? Pin
Nicholas Seward26-Aug-07 6:58
Nicholas Seward26-Aug-07 6:58 
GeneralRe: Does it work with VB .Net ? Pin
Patrice Dargenton27-Aug-07 1:54
Patrice Dargenton27-Aug-07 1:54 
GeneralMDI child Pin
mcaos15-Aug-07 4:10
professionalmcaos15-Aug-07 4:10 
GeneralRe: MDI child Pin
Nicholas Seward16-Aug-07 14:42
Nicholas Seward16-Aug-07 14:42 
GeneralRe: MDI child Pin
mcaos16-Aug-07 21:56
professionalmcaos16-Aug-07 21:56 
GeneralCool... Pin
dgauerke13-Aug-07 8:41
dgauerke13-Aug-07 8:41 
but instead of deriving from a Form, why not use an ExtenderProvider so it can be dropped on any type of form. I converted your code into an ExtenderProvider, but it's in VB.net because of a current project (sorry Poke tongue | ;-P ). I have not completely tested the code yet, but it seems to be working properly. Let me know if there are any problems.

Imports System.ComponentModel

<provideproperty("faderproperties", gettype(control))=""> _
Public Class FaderExtender
Implements IExtenderProvider, ISupportInitialize

Friend _Initializing As Boolean = False
Private _Properties As New Dictionary(Of Control, FaderProperties)

<designerserializationvisibility(designerserializationvisibility.content)> _
<defaultvalue(gettype(faderproperties), "nothing")=""> _
<category("fader")> _
<extenderprovidedproperty()> _
Public Function GetFaderProperties(ByVal ctrl As Control) As FaderProperties
If _Properties.ContainsKey(ctrl) Then
Return _Properties(ctrl)
Else
_Properties.Add(ctrl, New FaderProperties(ctrl))
Return _Properties(ctrl)
End If
End Function

Public Sub SetFaderProperties(ByVal ctrl As Control, ByVal value As FaderProperties)
Dim props As FaderProperties = Nothing

If value Is Nothing Then
If _Properties.ContainsKey(ctrl) Then
props = _Properties(ctrl)
props.Detach()
_Properties.Remove(ctrl)
End If
Else
If _Properties.ContainsKey(ctrl) Then
props = _Properties(ctrl)
props.Detach()
_Properties(ctrl) = value
Else
_Properties.Add(ctrl, value)
End If
If Not value._Target Is Nothing Then
value.Detach()
End If
value._Target = ctrl
value.Attach()
End If
End Sub

Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend
If TypeOf extendee Is Form AndAlso Not (TypeOf extendee Is FaderExtender) Then
Return True
End If
Return False
End Function

Public Sub BeginInit() Implements System.ComponentModel.ISupportInitialize.BeginInit
_Initializing = True
End Sub

Public Sub EndInit() Implements System.ComponentModel.ISupportInitialize.EndInit
For Each fp As FaderProperties In _Properties.Values
fp._Initializing = False
fp.TargetOpacity = fp.TargetOpacity
Next
_Initializing = False
End Sub

<typeconverter(gettype(expandableobjectconverter))> _
Public Class FaderProperties

Friend _Target As Form
Private _Native As FaderWindow
Friend _Initializing As Boolean = True

Private _targetOpacity As Double
Private _fadeTime As Double = 0.35
Friend _activeOpacity As Double = 1.0
Private _inactiveOpacity As Double = 1.0
Friend _minimizedOpacity As Double = 0
Private _timer As System.Windows.Forms.Timer

Public Sub New(ByVal Target As Form)
If Not _Target Is Nothing Then
Detach()
End If
_Target = Target
Attach()
End Sub

<notifyparentproperty(true)> _
<browsable(false)> _
<designerserializationvisibility(designerserializationvisibility.hidden)> _
Public Property TargetOpacity() As Double
Get
Return _targetOpacity
End Get
Set(ByVal value As Double)
_targetOpacity = value
If _Initializing Then Return
If Not _timer.Enabled Then
_timer.Start()
End If
End Set
End Property

<notifyparentproperty(true)> _
Public Property FadeTime() As Double
Get
Return _fadeTime
End Get
Set(ByVal value As Double)
If (value > 0) Then
_fadeTime = value
Else
_fadeTime = 0.1
End If
End Set
End Property

<notifyparentproperty(true)> _
Public Property ActiveOpacity() As Double
Get
Return _activeOpacity
End Get
Set(ByVal value As Double)
If (value >= 0) Then
_activeOpacity = value
Else
_activeOpacity = 100.0
End If
If (_Target.ContainsFocus) Then
TargetOpacity = ActiveOpacity
End If
End Set
End Property

<notifyparentproperty(true)> _
Public Property InactiveOpacity() As Double
Get
Return _inactiveOpacity
End Get
Set(ByVal value As Double)
If (value >= 0) Then
_inactiveOpacity = value
Else
_inactiveOpacity = 100.0
End If
If (Not _Target.ContainsFocus AndAlso _Target.WindowState <> FormWindowState.Minimized) Then
TargetOpacity = InactiveOpacity
End If
End Set
End Property

<notifyparentproperty(true)> _
Public Property MinimizedOpacity() As Double
Get
Return _minimizedOpacity
End Get
Set(ByVal value As Double)
If (value >= 0) Then
_minimizedOpacity = value
Else
_minimizedOpacity = 100.0
End If
If (Not _Target.ContainsFocus AndAlso _Target.WindowState <> FormWindowState.Minimized) Then
TargetOpacity = InactiveOpacity
End If
End Set
End Property

Friend Sub Attach()
_Native = New FaderWindow(Me)
_Native.AssignHandle(_Target.Handle)

_timer = New System.Windows.Forms.Timer()
_timer.Interval = 25
AddHandler _timer.Tick, AddressOf timer_Tick
AddHandler _Target.Deactivate, AddressOf FadeForm_Deactivate
AddHandler _Target.Activated, AddressOf FadeForm_Activated
AddHandler _Target.Load, AddressOf FadeForm_Load
End Sub

Public Sub Detach()
If Not _timer Is Nothing Then
_timer.Stop()
RemoveHandler _timer.Tick, AddressOf timer_Tick
End If
If Not _Native Is Nothing Then
_Native.ReleaseHandle()
_Native = Nothing
End If
If Not _Target Is Nothing Then
RemoveHandler _Target.Deactivate, AddressOf FadeForm_Deactivate
RemoveHandler _Target.Activated, AddressOf FadeForm_Activated
RemoveHandler _Target.Load, AddressOf FadeForm_Load
End If
End Sub

Private Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
Dim fadeChangePerTick As Double = _timer.Interval * 1.0 / 1000.0 / _fadeTime

'Check to see if it is time to stop the timer
If (Math.Abs(TargetOpacity - _Target.Opacity) < fadeChangePerTick) Then
'There is an ugly black flash if you set the Opacity to 1.0
If (_targetOpacity = 1.0) Then
_Target.Opacity = 0.999
Else
_Target.Opacity = _targetOpacity
End If
'Process held Windows Message.
_Native.LocalWndProc(_Native.HeldMessage)
_Native.HeldMessage = New Message()
'Stop the timer to save processor.
_timer.Stop()
ElseIf (_targetOpacity > _Target.Opacity) Then
_Target.Opacity += fadeChangePerTick
ElseIf (_targetOpacity < _Target.Opacity) Then
_Target.Opacity -= fadeChangePerTick
End If
End Sub

Private Sub FadeForm_Load(ByVal sender As Object, ByVal e As EventArgs)
_Target.Opacity = _minimizedOpacity
TargetOpacity = _activeOpacity
End Sub

Private Sub FadeForm_Deactivate(ByVal sender As Object, ByVal e As EventArgs)
TargetOpacity = _inactiveOpacity
End Sub

Private Sub FadeForm_Activated(ByVal sender As Object, ByVal e As EventArgs)
TargetOpacity = _activeOpacity
End Sub
End Class

Private Class FaderWindow
Inherits System.Windows.Forms.NativeWindow

Private _heldMessage As New Message()
Private _Parent As FaderProperties

Private Const WM_SYSCOMMAND As Integer = &H112
Private Const WM_COMMAND As Integer = &H111
Private Const SC_MINIMIZE As Integer = &HF020
Private Const SC_RESTORE As Integer = &HF120
Private Const SC_CLOSE As Integer = &HF060

Public Property HeldMessage() As Message
Get
Return _heldMessage
End Get
Set(ByVal value As Message)
_heldMessage = value
End Set
End Property

Public Sub New(ByVal Parent As FaderProperties)
_Parent = Parent
End Sub

Friend Sub LocalWndProc(ByRef m As Message)
MyBase.WndProc(m)
End Sub

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If (m.Msg = WM_SYSCOMMAND OrElse m.Msg = WM_COMMAND) Then
'Fade to zero on minimze
If (m.WParam.ToInt32 = SC_MINIMIZE) Then
If (_heldMessage.WParam.ToInt32 <> SC_MINIMIZE) Then
_heldMessage = m
_Parent.TargetOpacity = _Parent._minimizedOpacity
Else
_heldMessage = New Message()
_Parent.TargetOpacity = _Parent._activeOpacity
End If
Return

'Fade in if the window is restored from the taskbar
ElseIf (m.WParam.ToInt32 = SC_RESTORE AndAlso _Parent._Target.WindowState = FormWindowState.Minimized) Then
MyBase.WndProc(m)
_Parent.TargetOpacity = _Parent._activeOpacity
Return

'Fade out if the window is closed.
ElseIf (m.WParam.ToInt32 = SC_CLOSE) Then
_heldMessage = m
_Parent.TargetOpacity = _Parent._minimizedOpacity
Return
End If
End If

MyBase.WndProc(m)
End Sub
End Class
End Class
GeneralRe: Cool... Pin
Nicholas Seward13-Aug-07 19:04
Nicholas Seward13-Aug-07 19:04 
GeneralRe: Cool... Pin
ddmccrory16-Aug-07 1:26
ddmccrory16-Aug-07 1:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.