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