Making a Splash
As you saw in the previous section, the code needed to use the splash form is quite simple. All the complicated details are hidden inside the form itself.
Keeping the main program simple makes it easier to reuse this form in new prototypes. All you need to do is add the form to the new project, and insert code in the main program's Load event handler and the Help menu's About command. The splash form does the rest. Of course, you'll want to make changes to the splash form so it doesn't look the same in all of your programs, but those changes are localized in the form's code so you can't accidentally interfere with the main program's code when you make them. They are also pretty fun so they don't seem like a chore.
The following sections describe the splash form's most interesting pieces of code. They do not show all of the form's variable and API declarations because they are not very interesting. You can see all of the code in its full glory by clicking here to download the example project.
The splash form contains three controls: lblOk, tmrUnload, and picLink. The lblOk label displays the white Ok text shown in Figure 2.
The timer tmrUnload unloads the form when its Timer event fires. At design time, I have set tmrUnload's Interval property to 3000 so it unloads the form after 3000 milliseconds (three seconds).
The picLink PictureBox is hidden and contains the mouse pointer displayed when the mouse is over the text http://www.vb-helper.com. You'll learn more about how this works a little later.
Listing 1 shows the splash form's ShowAbout and ShowSplash methods. ShowAbout moves lblOk to the correct position and makes it visible so the user can click it to close the dialog. It disables tmrUnload so the timer does not unload the form automatically. ShowAbout then calls the SetWindowPos API function to make the form a topmost form. That means no other form (except possibly other topmost forms) can ever be on top of it. The routine sets the form's m_IsAboutDialog property to True so it knows the form is being displayed as an about dialog box. ShowAbout then displays the form modally.
The ShowSplash routine begins by hiding lblOk so the user cannot click on it to close the splash screen. It enables tmrUnload so that control's Timer event automatically unloads the form after three seconds.
Next, ShowSplash disables the program's main form. This prevents the user from interacting with the form until the splash screen unloads. Most programs start with a single form so you can easily disable it. If you have more than one form showing, however, you need to disable them all. You could loop through the Forms collection, disabling all the forms except the splash form. This example is complicated enough already, so I'll leave that to you.
ShowSplash then calls the SetWindowPos API function to make its form topmost, sets m_IsAboutDialog to False, and displays the form. This routine displays the form non-modally so the main form's Form_Load event handler can continue executing. That lets the program load configuration parameters, connect to databases, and do any other necessary initialization tasks while the splash screen is visible.
Listing 1 The ShowAbout and ShowSplash Methods Display the Splash Form
' Display the form as an about dialog. Public Sub ShowAbout() ' Show the Ok label and disable the unload timer. lblOk.Move 745, 243 lblOk.Visible = True tmrUnload.Enabled = False ' Keep the form on top. SetWindowPos hwnd, _ HWND_TOPMOST, 0, 0, 0, 0, _ SWP_NOMOVE + SWP_NOSIZE ' Display the form modally. m_IsAboutDialog = True Me.Show vbModal End Sub ' Display the form as a splash screen. Public Sub ShowSplash() ' Hide the Ok label and enable the unload timer. lblOk.Visible = False tmrUnload.Enabled = True ' Disable the main program. frmTestSplash.Enabled = False ' Keep the form on top. SetWindowPos hwnd, _ HWND_TOPMOST, 0, 0, 0, 0, _ SWP_NOMOVE + SWP_NOSIZE ' Display the form non-modally. m_IsAboutDialog = False Me.Show End Sub
The splash form unloads in three different ways, depending on whether it was displayed as a splash screen or as an about dialog box. Listing 2 shows the code that handles the different cases.
When the ShowAbout method displays the form as an about dialog box, it makes the lblOk control visible so the user can click on it. It disables tmrUnload so that control's Timer event doesn't unload the form. The lblOk_Click event handler shown in Listing 2 simply unloads the splash form. ShowAbout does not disable the program's main form, so the lblOk_Click event handler doesn't need to re-enable the form.
When the user presses a key, the form's KeyPress event handler fires checks the m_IsAboutDialog variable to see how the form is being displayed. ShowAbout sets m_IsAboutDialog to True, so when the form is displayed as an about dialog box, the KeyPress event handler unloads the form if the user pressed the Return or Escape key.
When the ShowSplash method displays the form as a splash screen, it enables the tmrUnload control. After three seconds, that control's Timer event fires. The tmrUnload_Timer event handler shown in Listing 2 re-enables the program's main form and unloads the splash form.
ShowSplash hides the lblOk control so the user cannot click on it. It also sets m_IsAboutDialog to False, so the form's KeyPress event handler does not unload the form. The only way the splash screen unloads is when tmrUnload's Timer event fires.
Listing 2 The Splash Form Unloads when tmrUnload's Timer Event Fires, when the User Clicks lblOk, or when the usEr Presses Escape or Return
' The splash screen has been visible long enough. ' Unload it. Private Sub tmrUnload_Timer() Unload Me ' Reenable the main program's form. frmTestSplash.Enabled = True End Sub ' The user clicked the about form's Ok label. ' Unload the form. Private Sub lblOk_Click() Unload Me End Sub ' If we are displayed as an about dialog, unload if ' the user presses Escape or Return. Private Sub Form_KeyPress(KeyAscii As Integer) If m_IsAboutDialog Then If KeyAscii = vbKeyEscape Or _ KeyAscii = vbKeyReturn _ Then Unload Me End If End If End Sub
Cursors, Cursors Everywhere
Normally, the splash form displays the default arrow mouse cursor pointing up and to the left. When the mouse moves over the Ok button, the form changes the mouse cursor to a left-pointing hand. This part is easy. At design time, I set the lblOk control's MousePointer property to Custom and its MouseIcon property to an icon file containing the left-pointing hand. When the mouse moves over the control, Visual Basic changes the cursor automatically.
When the mouse moves over the text http://www.vb-helper.com, the program changes the mouse cursor to an upward-pointing hand. Listing 3 shows how this works. When the mouse moves, the MouseMove event handler calls function OverHotSpot to see if the mouse is over the text. The variables m_HotSpotXmin, m_HotSpotXmax, m_HotSpotYmin, and m_HotSpotYmax that bound the text are set by the ShapeForm routine discussed later.
If OverHotSpot returns True, the program sets the mouse pointer to the upward-pointing hand contained in the picLink PictureBox. If the mouse is not over the hotspot, the program resets the mouse pointer to the default arrow.
Listing 3 When the Mouse is Over the URL Hotspot, the Program Changes the mouse Pointer to an Upward-Pointing Hand
' Display an appropriate mouse cursor. Private Sub Form_MouseMove(Button As Integer, Shift As Integer, _ X As Single, Y As Single) If OverHotspot(X, Y) Then ' We're over the hotspot. ' Display a hand. If MousePointer <> vbCustom Then MouseIcon = picLink.Picture MousePointer = vbCustom End If Else ' We're not over the hotspot. ' Display the default cursor. If MousePointer <> vbDefault Then MousePointer = vbDefault End If End If End Sub ' Return True if the mouse is over the hotspot. Private Function OverHotspot(ByVal X As Single, ByVal Y As Single) _ As Boolean OverHotspot = _ X >= m_HotSpotXmin And _ X <= m_HotSpotXmax And _ Y >= m_HotSpotYmin And _ Y <= m_HotSpotYmax End Function
I Might As Well Jump
When the user clicks on the http://www.vb-helper.com hotspot, the program jumps to the VB Helper home page, displaying it in the system's default browser. This is one of those impressive special effects that takes practically no effort on your part.
When the user clicks on the form, the MouseDown event handler fires. This routine performs one of two tasks. If the condition shown in Listing 4 is True, the routine prints the mouse's coordinates in the Debug window. You can use these coordinates during development to figure out where to place controls. For example, I set this condition to True, clicked where I wanted to position the lblOk control, and then used the coordinates displayed in the Debug window to move lblOk where it belonged in the ShowAbout subroutine. Similarly, I used this trick to figure out where to put the rounded rectangle containing the program's version and copyright information shown in Figures 1 and 2.
If the condition is False, as it should be when you show the prototype to your customers, the Form_MouseDown event handler uses the OverHotSpot function to see if the mouse is over the text hotspot. If the mouse is over the text, the program uses the ShellExecute API function to open the URL. ShellExecute automatically displays the URL in the system's default browser.
Listing 4 When the User Clicks on the Hotspot, the Program Displays the URL in the System's Default Browser
' Display a Web address or print the coordinates ' clicked. ' This is how I decided where to place things on ' the form. Private Sub Form_MouseDown(Button As Integer, Shift As Integer, _ X As Single, Y As Single) ' Change to True to display coordinates clicked. If False Then Debug.Print X; Y Else If OverHotspot(X, Y) Then _ ShellExecute hwnd, "open", "http://" & LINK_URL, _ vbNullString, vbNullString, SW_SHOW End If End Sub
Before I describe the ShapeForm routine that gives the form its interesting outline, you should know about the CustomFont subroutine shown in Listing 5. CustomFont uses the CreateFont API function to build a customized font and return the font's handle. ShapeForm then installs the font and uses it to draw the splash form's text.
CreateFont is one of the most complicated API functions taking 14 parameters.
It lets you build fonts in all different sizes, bold,
strikenthrough, and rotated. I won't cover all
of this function's details here, but I do want to mention TrueType
TrueType fonts are designed to be stretched, scaled, and rotated. Instead of containing a bitmap defining its characters, a TrueType font contains instructions for drawing the lines and curves that make up its letters. The font mapper can scale, stretch, and rotate those instructions to produce a huge variety of fonts at different sizes and with different orientations.
If you make CreateFont work with a non-TrueType font, the font mapper may be unable to produce the result you want. For example, CreateFont can rotate the TrueType font Times New Roman, but not the font MS Sans Serif. If you try to rotate MS Sans Serif, you get a normal horizontal font.
There are several ways to decide which fonts to use. First, you can use the fonts Arial, Courier New, Times New Roman and Symbol. They are TrueType fonts, and are present on most Windows systems.
To see a list of your computer's TrueType fonts, select a form's Font property and click the ellipsis to the right to make Visual Basic display a font selection dialog box. This dialog box places a TT to the left of the names of TrueType fonts.
You can also try using a font in your splash screen, and see if it rotates properly. If the font doesn't work, use a different font.
For more information on CreateFont, consult the MSDN documentation or see http://www.vb-helper.com/vbgp.htm.
Listing 5 The CreateFont API Function Can Make Fonts that are Scaled, Stretched, Squashed, or Rotated
' Make a customized font and return its handle. Private Function CustomFont(ByVal hgt As Long, ByVal wid As Long, _ ByVal escapement As Long, ByVal orientation As Long, _ ByVal wgt As Long, ByVal is_italic As Long, _ ByVal is_underscored As Long, ByVal is_striken_out As Long, _ ByVal face As String) As Long Const CLIP_LH_ANGLES = 16 ' Needed for tilted fonts. CustomFont = CreateFont( _ hgt, wid, escapement, orientation, wgt, _ is_italic, is_underscored, is_striken_out, _ 0, 0, CLIP_LH_ANGLES, 0, 0, face) End Function