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.ActiveOpacity=1;
this.InactiveOpacity=.85;
this.MinimizedOpacity=0;
You may, from time to time, want to disable the fade effect.
this.DisableFade();
this.EnableFadeDefaults();
You can also change the transition time.
this.FadeTime=1;
You can also do a one-time fade to any value.
this.TargetOpacity=.25;
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;
protected override void WndProc(ref Message m)
{
if (m.Msg==WM_SYSCOMMAND||m.Msg == WM_COMMAND)
{
if (m.WParam == (IntPtr)SC_MINIMIZE)
{
heldMessage = m;
this.TargetOpacity = minimizedOpacity;
return;
}
else if (m.WParam == (IntPtr)SC_RESTORE
&& this.WindowState == FormWindowState.Minimized)
{
base.WndProc(ref m);
this.TargetOpacity = activeOpacity;
return;
}
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.
private void timer_Tick(object sender, EventArgs e)
{
double fadeChangePerTick = timer.Interval * 1.0 / 1000 / fadeTime;
if (Math.Abs(targetOpacity - this.Opacity) < fadeChangePerTick)
{
if (targetOpacity == 1) this.Opacity = .999;
else this.Opacity = targetOpacity;
base.WndProc(ref heldMessage);
heldMessage = new Message();
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