Click here to Skip to main content
Licence CPOL
First Posted 13 Aug 2007
Views 54,449
Downloads 319
Bookmarked 82 times

Fading Forms In and Out

By | 13 Aug 2007 | Article
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.

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.

//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.

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

You can also change the transition time.

this.FadeTime=1; //1 sec transition

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

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.

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.

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.

//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.

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)

About the Author

Nicholas Seward

Instructor / Trainer

United States United States

Member

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.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Generalblack flash Pinmemberroundy729:23 15 Mar '09  
GeneralRe: black flash PinmemberNicholas Seward15:49 15 Mar '09  
GeneralRe: black flash PinmemberAtanas Palavrov16:37 1 Apr '09  
GeneralRe: black flash PinmemberAtanas Palavrov9:14 12 May '09  
GeneralRe: black flash [modified] PinmemberNicholas Seward10:13 12 May '09  
GeneralRe: black flash PinmemberAtanas Palavrov3:54 14 May '09  
GeneralRe: black flash PinmemberNicholas Seward5:49 14 May '09  
GeneralSystem ERROR Occured in Application Pinmembercoolpul2:50 6 Sep '08  
General.999 opacity and layout execution time Pinmembernukefusion4:10 26 Nov '07  
GeneralGeneral Comments Pinmemberchris1752:25 22 Aug '07  
GeneralRe: General Comments PinmemberNicholas Seward7:05 26 Aug '07  
GeneralRe: General Comments Pinmemberchris1751:13 27 Aug '07  
I am really interested in getting your updated version.
 
I guess the main reason for using OnActivated and OnDeactivated is for deriving classes. If you derive a class from FadeForm (I don’t know why anyone would ever do this) you can override the OnActivated and OnDeactivated and choose to run code before and/or after the derived classes OnActivated and OnDeactivated.
 
Also I am noticing while resizing the window there is "black" space. This is just a minor issue.
 
This is my new FadeForm.cs and may give you some ideas to incorporate in your code. It may also show something wrong with my code. Please note the [RefreshProperties(RefreshProperties.All)] attribute on the MinimizedOpacity property. Because the MinimizedOpacity property changes another property you would want to refresh that other property on the property grid in the design window. I am also not sure of all the properties that could use the ArgumentOutOfRangeException to validate the value coming into the property.
 
Have fun...
 
using System;
using System.ComponentModel;
using System.Windows.Forms;
 
namespace Test
{
   /// <summary>
   /// A form that fades in and out.
   /// </summary>
   public class FadeForm : Form
   {
      #region WindowsMessageCodes
      private const int WMSysCommand = 0x112;
      private const int WMCommand = 0x111;
      private const int SCMinimize = 0xF020;
      private const int SCRestore = 0xF120;
      private const int SCClose = 0xF060;
      #endregion
 
      #region Variables
      /// <summary>
      /// WindowsMessage that is being held until the end of a transition.
      /// </summary>
      private Message _HeldMessage = new Message();
 
      /// <summary>
      /// Timer to aid in fade effects.
      /// </summary>
      private System.Windows.Forms.Timer _Timer;
      #endregion
 
      #region Properties
      #region ActiveOpacity
      private double _ActiveOpacity = 1;
      /// <summary>
      /// Gets or sets the opacity that the form will transition to when the form gets focus which must be a positive number.
      /// </summary>
      /// <exception cref="ArgumentOutOfRangeException">Thrown if this property is not set to a positive value.</exception>
      [Category("Custom")]
      [Description("The opacity that the form will transition to when the form gets focus which must be a positive number.")]
      [RefreshProperties(RefreshProperties.All)]
      public double ActiveOpacity
      {
         get { return _ActiveOpacity; }
         set
         {
            if (value >= 0)
               _ActiveOpacity = value;
            else
               throw new ArgumentOutOfRangeException("value", Properties.Resources.ErrorActiveOpacity);
            
            if (ContainsFocus)
               TargetOpacity = _ActiveOpacity;
         }
      }
      #endregion
 
      #region FadeTime
      private double _FadeTime = 0.35;
      /// <summary>
      /// Gets or sets the time it takes to fade from 0 to 1 or the other way around.
      /// </summary>
      /// <exception cref="ArgumentOutOfRangeException">Thrown if this property is not set to a positive value between 0 and 1.</exception>
      [Category("Custom")]
      [Description("The time it takes to fade from 0 to 1 or the other way around.")]
      public double FadeTime
      {
         get { return _FadeTime; }
         set
         {
            if (value > 0 && value < 1)
               _FadeTime = value;
            else
               throw new ArgumentOutOfRangeException("value", Properties.Resources.ErrorFadeTime);
         }
      }
      #endregion
 
      #region InactiveOpacity
      private double _InactiveOpacity = .85;
      /// <summary>
      /// Gets or sets the opacity that the form will transition to when the form doesn't have focus.
      /// </summary>
      /// <exception cref="ArgumentOutOfRangeException">Thrown if this property is not set to a value greater than or equal to 0.</exception>
      [Category("Custom")]
      [Description("The opacity that the form will transition to when the form doesn't have focus.")]
      [RefreshProperties(RefreshProperties.All)]
      public double InactiveOpacity
      {
         get { return _InactiveOpacity; }
         set
         {
            if (value >= 0)
               _InactiveOpacity = value;
            else
               throw new ArgumentOutOfRangeException("value", Properties.Resources.ErrorInactiveOpacity);
            
            if (!ContainsFocus && WindowState != FormWindowState.Minimized)
               TargetOpacity = _InactiveOpacity;
         }
      }
      #endregion
 
      #region MinimizedOpacity
      private double _MinimizedOpacity;
      /// <summary>
      /// Gets or sets the opacity that the form will transition to when the form is minimized.
      /// </summary>
      /// <exception cref="ArgumentOutOfRangeException">Thown if this property is not set to a value greater than or equal to 0.</exception>
      [Category("Custom")]
      [Description("The opacity that the form will transition to when the form is minimized.")]
      [RefreshProperties(RefreshProperties.All)]
      public double MinimizedOpacity
      {
         get { return _MinimizedOpacity; }
         set
         {
            if (value >= 0)
               _MinimizedOpacity = value;
            else
               throw new ArgumentOutOfRangeException("value", Properties.Resources.ErrorMinimizedOpacity);
            
            if (!ContainsFocus && WindowState != FormWindowState.Minimized)
               TargetOpacity = InactiveOpacity;
         }
      }
      #endregion
 
      #region TargetOpacity
      private double _TargetOpacity;
      /// <summary>
      /// Gets or sets the opacity the form is transitioning to.
      /// </summary>
      [Category("Custom")]
      [Description("The opacity the form is transitioning to.")]
      public double TargetOpacity
      {
         get { return _TargetOpacity; }
         set
         {
            _TargetOpacity = value;
            if (!_Timer.Enabled)
               _Timer.Start();
         }
      }
      #endregion
      #endregion
 
      #region Constructor
      /// <summary>
      /// Constructor
      /// </summary>
      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Mobility", "CA1601:DoNotUseTimersThatPreventPowerStateChanges", Scope = "member", Target = "FadeForm.FadeForm..ctor()")]
      public FadeForm()
      {
         this._Timer = new System.Windows.Forms.Timer();
         this.SuspendLayout();
         this._Timer.Interval = 25;
         this._Timer.Tick += new System.EventHandler(this._Timer_Tick);
      }
      #endregion
 
      #region DisableFade
      /// <summary>
      /// Turns off opacitiy fading.
      /// </summary>
      public void DisableFade()
      {
         ActiveOpacity = 1;
         InactiveOpacity = 1;
         MinimizedOpacity = 1;
      }
      #endregion
 
      #region EnableFadeDefaults
      /// <summary>
      /// Turns on opacitiy fading.
      /// </summary>
      public void EnableFadeDefaults()
      {
         ActiveOpacity = 1;
         InactiveOpacity = .85;
         MinimizedOpacity = 0;
         FadeTime = .35;
      }
      #endregion
 
      #region WndProc
      /// <summary>
      /// Intercepts WindowMessages before they are processed.
      /// </summary>
      /// <param name="m">Windows Message</param>
      [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
      protected override void WndProc(ref Message m)
      {
         if (m.Msg == WMSysCommand || m.Msg == WMCommand)
         {
            //Fade to zero on minimze
            if (m.WParam == (IntPtr)SCMinimize)
            {
               if (_HeldMessage.WParam != (IntPtr)SCMinimize)
               {
                  _HeldMessage = m;
                  TargetOpacity = MinimizedOpacity;
               }
               else
               {
                  _HeldMessage = new Message();
                  TargetOpacity = ActiveOpacity;
               }
               return;
            }
 
           //Fade in if the window is restored from the taskbar
            else if (m.WParam == (IntPtr)SCRestore
                && this.WindowState == FormWindowState.Minimized)
            {
               base.WndProc(ref m);
               TargetOpacity = ActiveOpacity;
               return;
            }
 
           //Fade out if the window is closed.
            else if (m.WParam == (IntPtr)SCClose)
            {
               _HeldMessage = m;
               TargetOpacity = MinimizedOpacity;
               return;
            }
         }
 
         base.WndProc(ref m);
      }
      #endregion
 
      #region _Timer
      /// <summary>
      /// Called when the timer ticks.
      /// </summary>
      /// <param name="sender">Unused.</param>
      /// <param name="e">Unused.</param>
      private void _Timer_Tick(object sender, EventArgs e)
      {
         //Performs fade increment.
         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;
      }
      #endregion
 
      #region Activated
      /// <summary>
      /// Called when the form is activated.
      /// </summary>
      /// <param name="e">Unused.</param>
      protected override void OnActivated(EventArgs e)
      {
         base.OnActivated(e);
 
         //Fade in the form when it gaines focus.
         TargetOpacity = ActiveOpacity;
      }
      #endregion
 
      #region OnDeactivate
      /// <summary>
      /// Called when the form is deactivating.
      /// </summary>
      /// <param name="e">Unused.</param>
      protected override void OnDeactivate(EventArgs e)
      {
         base.OnDeactivate(e);
 
         //Fade out the form when it losses focus.
         this.TargetOpacity = InactiveOpacity;
      }
      #endregion
 
      #region OnLoad
      /// <summary>
      /// Called when the form is loading.
      /// </summary>
      /// <param name="e">Unused.</param>
      protected override void OnLoad(EventArgs e)
      {
         base.OnLoad(e);
         
         //Causes the form to fade in.
         this.Opacity = MinimizedOpacity;
         TargetOpacity = ActiveOpacity;
      }
      #endregion
   }
}

 
Chris
GeneralRe: General Comments PinmemberNicholas Seward4:46 27 Aug '07  
GeneralRe: General Comments Pinmemberchris1758:44 27 Aug '07  
GeneralRe: General Comments PinmemberNicholas Seward10:25 27 Aug '07  
GeneralRe: General Comments Pinmemberchris1758:54 27 Aug '07  
QuestionDoes it work with VB .Net ? PinmemberPatrice Dargenton0:26 22 Aug '07  
AnswerRe: Does it work with VB .Net ? PinmemberNicholas Seward6:58 26 Aug '07  
GeneralRe: Does it work with VB .Net ? PinmemberPatrice Dargenton1:54 27 Aug '07  
GeneralMDI child PinmemberWindows M4:10 15 Aug '07  
GeneralRe: MDI child PinmemberNicholas Seward14:42 16 Aug '07  
GeneralRe: MDI child PinmemberWindows M21:56 16 Aug '07  
GeneralCool... Pinmemberdgauerke8:41 13 Aug '07  
GeneralRe: Cool... PinmemberNicholas Seward19:04 13 Aug '07  
GeneralRe: Cool... Pinmemberddmccrory1:26 16 Aug '07  

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

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120529.1 | Last Updated 13 Aug 2007
Article Copyright 2007 by Nicholas Seward
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid