(Print this page)

Windows Forms Effect
Published date: Monday, July 6, 2009
On: Moer and Éric Moreau's web site

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.


(Print this page)