I often see people in newsgroup asking how they can add some effects to their forms. I found a couple of ways, some good and ... some not so good! This article will show you how to animate, fade, flash, and nudge a form of your application.
Some of those tricks are not intrinsic to .Net but exist in Windows itself so we need to invoke the Windows functions directly (here PInvoke is of great help).
The downloadable example
Instead of mixing all the code for each effect into a single form, I have created one form for each of them. So if you want to see how to “nudge” a form, you just have to open the fNudge form and you find everything required.
Figure 1: The demo application in action
Even if the code shown in this article is all in VB.Net, the downloadable code is provided in both VB and C# for your convenience.
The menu form
Do not look for tricks in this form it has none. This form is a plain list of buttons used to show the forms that really have something special.
The Fade effect
This effect is native to the .Net Framework. Forms have a property called Opacity which accepts a value between 0.0 (for complete transparency) and 1.0 (for complete opacity).
To create a fade in or fade out effect, we can vary the value of the Opacity property in a tight loop.
My demo fFade form contains a button that we will use to close the form and a Timer control that we will use to change the Opacity property.
In the Load event of the form, I set the Opacity to 0 to have my form fully transparent, set a variable (mblnFormIsLoading) to True (used in the timer to detect if the form is loading or closing) and start the timer. When the user clicks the Close button, set a variable (mblnFormIsLoading) to False (meaning that we are closing the form) and start the timer. So you understand that the interesting code is in the Tick event of the timer.
Because the Interval property of the Timer is set to 1 millisecond, the Tick even will be raised very quickly. I increment (or decrement) the Opacity property of the form by 0.01 (which is 1%) every 1 millisecond. We need to detect that the form is fully transparent or fully opaque and stop the timer. If you set the Opacity to 2, no errors will occur but the form won’t be more opaque then if the value is 1.
This is the complete listing for this form:
'Hold a value saying if the form is loading or closing
Private mblnFormIsLoading As Boolean
Private Sub fFade_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Timer1.Interval = 1 'Set the timer interval to 1 millisecond
Me.Opacity = 0 'Full transparency
mblnFormIsLoading = True 'Set the value to loading
Timer1.Enabled = True 'Start the timer
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If mblnFormIsLoading Then
'When the form is loading
Me.Opacity += 0.01
'When the Opacity is 1 (full), we need to stop the timer
If Me.Opacity = 1 Then Timer1.Enabled = False
Else
'When the is closing
Me.Opacity -= 0.01
'When the Opacity is 0 (transparent), we need to stop the timer and close the form
If Me.Opacity = 0 Then
Timer1.Enabled = False
Me.Close()
End If
End If
End Sub
Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click
mblnFormIsLoading = False 'Set the value to closing
Timer1.Enabled = True 'Start the timer
End Sub
Be aware that this effect will only run on Windows 2000 and higher. Setting the Opacity property on older Windows system (if you still have to support some of them) has no effect.
The Gradient background
This isn’t a form’s effect per say but it is something nice and really easy to achieve. Instead of the dull gray background color, you can put a gradient colorized background. Because I use a linear gradient brush, we will get a nice gradient effect instead of a solid color.
You need to define a rectangle object (my ORAngle variable) which is almost always the full size of your form.
You also need to define a brush object (my oBrush variable). The constructor parameters of the brush are:
- The zone to which you want to apply the brush (our Rectangle object we just created).
- The starting color for the gradient.
- The ending color for the gradient.
- The orientation of the gradient.
You finally need to call the FillRectangle method and clean up your objects.
This is the code you need into the form’s Paint event:
'Creating a new Rectangle as similar width and height of the base form
Dim oRAngle As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
'Creating a new Gradient style brush.
'Change the colors here to get different color combination.
'"Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal" can be changed accordingly
'to get different styles like ForwardDiagonal, Horizontal, Vertical.
Dim oBrush As Brush = New Drawing.Drawing2D.LinearGradientBrush( _
oRAngle, Color.Beige, Color.OrangeRed, _
Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal)
'With the help of fillrectangle function drawing rectangle in to form
e.Graphics.FillRectangle(oBrush, oRAngle)
'Clean up resources
oBrush.Dispose()
oBrush = Nothing
oRAngle = Nothing
That’s it. Less than 10 lines of code are required for a nice color background. One reason why I really like colorized background is to help be differentiate runtime environments (production, acceptance, test, ...).
The Animate effect
This is a nice effect but it is causing a small flickering that some people won’t like. If you find a way not to have the form to flicker that much, drop me a line!
This effect lets you slide a form much like PowerPoint slides.
This effect is not native to the .Net Framework so you need to import a couple of declarations from the Windows library:
<DllImport("user32.dll")> _
Private Shared Function AnimateWindow(ByVal hwnd As IntPtr, _
ByVal time As Integer, _
ByVal flags As AnimateWindowFlags) As Boolean
End Function
<Flags()> _
Private Enum AnimateWindowFlags
AW_HOR_POSITIVE = &H1
AW_HOR_NEGATIVE = &H2
AW_VER_POSITIVE = &H4
AW_VER_NEGATIVE = &H8
AW_CENTER = &H10
AW_HIDE = &H10000
AW_ACTIVATE = &H20000
AW_SLIDE = &H40000
AW_BLEND = &H80000
End Enum
Once you have that, you are ready to write a little wrapper method that we will call later:
Private Sub AnimateWin(ByVal frmToAnimate As Form, ByVal showForm As Boolean)
If showForm Then
AnimateWindow(frmToAnimate.Handle, 1000, _
AnimateWindowFlags.AW_HOR_NEGATIVE Or AnimateWindowFlags.AW_SLIDE)
Else
AnimateWindow(frmToAnimate.Handle, 1000, _
AnimateWindowFlags.AW_HOR_POSITIVE Or AnimateWindowFlags.AW_HIDE)
End If
End Sub
This wrapper method calls the AnimateWindow function declared previously. This method accepts 3 parameters:
- The handle of the form on which we want the effect.
- The duration of the effect in milliseconds.
- The effect itself where you can mix things like horizontal and sliding (like my example is doing). Try out the various combinations of positive/negative and horizontal/vertical settings.
The Flash effect
This is surely the most useful effect for me.
Just like the Animate effect, this one is also not native to the .Net Framework so you need to import a couple of declarations from the Windows library:
Private Declare Function FlashWindowEx Lib "User32" (ByRef FWInfo As FLASHWINFO) As Int32
Private Const FLASHW_STOP As Int32 = 0
Private Const FLASHW_CAPTION As Int32 = &H1&
Private Const FLASHW_TRAY As Int32 = &H2&
Private Const FLASHW_ALL As Int32 = FLASHW_CAPTION Or FLASHW_TRAY
Private Const FLASHW_TIMER As Int32 = &H4&
Private Const FLASHW_TIMERNOFG As Int32 = &HC&
Private Structure FLASHWINFO
Dim cbSize As Int32
Dim hwnd As IntPtr
Dim dwFlags As Int32
Dim uCount As Int32
Dim dwTimeout As Int32
End Structure
With those declarations, you are now ready to write a couple of handy wrappers like this:
Private Function FlashWindow(ByRef frm As Form) As Int32
Return FlashWindow(frm, True, True, 5)
End Function
Private Function FlashWindow(ByRef frm As Form, _
ByVal FlashTitleBar As Boolean, _
ByVal FlashTray As Boolean) As Int32
Return FlashWindow(frm, FlashTitleBar, FlashTray, 5)
End Function
Private Function FlashWindow(ByRef frm As Form, _
ByVal NumTimes2Flash As Integer) As Int32
Return FlashWindow(frm, True, True, NumTimes2Flash)
End Function
Private Function FlashWindow(ByRef frm As Form, _
ByVal FlashTitleBar As Boolean, _
ByVal FlashTray As Boolean, _
ByVal NumTimes2Flash As Integer) As Int32
Try
Dim fwi As New FLASHWINFO
With fwi
.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(fwi)
.hwnd = CType(IIf(frm Is Nothing, 0, frm.Handle), IntPtr)
If FlashTitleBar Then .dwFlags = .dwFlags Or FLASHW_CAPTION
If FlashTray Then .dwFlags = .dwFlags Or FLASHW_TRAY
.uCount = NumTimes2Flash
.dwTimeout = 250
End With
Return FlashWindowEx(fwi)
Catch
Return -1
End Try
End Function
The FlashWindowEx function requires a structure to be passed in its parameter. This structure is called here FlashWindow. Playing with the different values of this structure, you can make the form’s title bar to flash and/or the form’s icon on the taskbar, you can make it flash only a given number of time or until the form gets the focus, you can change the speed at which the flashing occurs, ...
With everything we have so far, we can simply call this line to have the form’s title bar and the icon in the taskbar flash 5 times:
FlashWindow(Me)
As I already told you, I often use this one.
The Nudge effect
All MSN Messenger users know this effect where the form is shaking. It is not very complex to reproduce this effect. All you need to do is to modify the location of the form quickly.
The code you need to achieve this effect is like the following:
Dim x As Integer = Me.Location.X
Dim y As Integer = Me.Location.Y
For i As Integer = 1 To 50
If (i Mod 2) = 0 Then Me.Location = New Point(x - 12, y)
Threading.Thread.Sleep(10)
If (i Mod 4) = 0 Then Me.Location = New Point(x - 24, y)
Threading.Thread.Sleep(10)
If (i Mod 8) = 0 Then Me.Location = New Point(x + 12, y)
Threading.Thread.Sleep(10)
If (i Mod 10) = 0 Then Me.Location = New Point(x + 12, y)
Threading.Thread.Sleep(10)
Next
Me.Location = New Point(x, y)
Conclusion
Effects on forms are nice but do not over abused from them. If you nudge every screen or make them all flash, it will make the “I need your attention” warning to disappear. Also remember that nudging the form is not very efficient if the user is not looking at the screen.