26_053416 ch19.qxd 1/2/07 6:36 PM Page 495

Splash Screens

The first thing a user sees of an application is its splash screen. As the adage says, “You only get one chance to make a first impression,” so it’s important that your splash screen represent your application appropriately. Though the user only gets one first impression of your application, the splash screen appears every time the application starts, so it’s important that it has a positive impact each time the user sees it.

A typical splash screen displays some basic information about the application such as its name, version number, and copyright information. Splash screens often provide contact information so that users can get technical support if necessary.

In addition to giving the user a little information, a splash screen gives the user something to look at while the application loads. At this point, the application might look for all sorts of resources such as databases, files, special devices, network connections, remotely mounted drives, Web Services, and so forth. It can connect to databases and open files, parse XML data, and otherwise get ready for business. If a program takes several seconds to do all this, then a splash screen shows the user that something is happening. If it includes a or status animation, it can let the user know that the program is working and has not become stuck.

The application can also perform security checks while the splash screen is visible. It can try to open password-protected databases, check the user’s credentials, and see if it can connect to the network through the user’s firewall.

In some applications, I have included user name and password text boxes on the splash screen so that the user can use it to log in. The splash screen’s code then checked a password database to verify that the user name and password were correct, and to see what kind of user this is (clerk, supervisor, manager, and so forth). The rest of the application used that information to configure itself, displaying or hiding menus and buttons as appropriate.

A well-crafted splash screen shows the users that you pay attention to details and makes an appli- cation look more professional. I usually build a splash screen for a new application as soon as development starts so that customers viewing prototypes can see it. In one application for the 26_053416 ch19.qxd 1/2/07 6:36 PM Page 496

Part IV: Specific Techniques

State of Minnesota, I made a splash screen in the shape of the state’s map. After the initial demonstra- tion, the first question they asked was, “How did you make that cool splash screen?” (The second question they asked was, “How long did it take?” They liked the splash screen but didn’t want to waste money on frills. As you’ll see in this chapter, making a shaped splash screen only takes a few minutes.)

This chapter explains how to build and use splash screens in Visual Basic. It tells how to add interesting and unusual features to a splash screen, such as a shaped form, rotated text, and text filled with a color gradient or pattern. Adding all of these features to every form in a project would probably make the application appear cluttered and distracting, but in a splash screen, they can make an otherwise utilitar- ian form more interesting.

Determining Splash Screen Contents Figure 19-1 shows the splash screen displayed by the ShapedSplashScreen example application. (You can download this example at www.vb-helper.com/one_on_one.htm.) The form is shaped to fit an image on the left and has rounded corners. It displays the application’s title eJack in outlined text that is filled with a color gradient shading from red to yellow to green (it looks much better on the screen than in this book). It displays the program’s version, serial number, and copyright information. It also displays a progress bar to show the user how far the application has proceeded in loading its data.

Figure 19-1: The ShapedSplashScreen program displays this splash screen when it starts.

The image on the left in Figure 19-1 was even generated by Visual Basic, specifically Visual Basic 6 code from my book, Visual Basic Graphics Programming: Hands-On Applications and Advanced Color Development, Second Edition (Indianapolis: Wiley, 1999).

A program’s About dialog should also display the same information. It should display the program’s name, version, serial number, and copyright statement. Because the About dialog contains the same information as the splash screen, it makes sense to use the same form for both.

Figure 19-2 shows the ShapedSplashScreen program displaying its About dialog. It is similar to the splash screen except that it doesn’t display a progress bar. It also displays a rotated link to the support Web site www.vb-helper.com and an OK so the user can close it. .

496 26_053416 ch19.qxd 1/2/07 6:36 PM Page 497

Chapter 19: Splash Screens

Figure 19-2: The About dialog displays much of the same information as the splash screen.

A splash screen should not display system information such as memory usage or disk space. To manage system resources, the user should use the operating system tools, not your application.

When a user needs help with an application, the technical support people usually need to know the pro- gram’s serial number. These numbers are often quite long (my Visual Basic serial number has 20 digits plus embedded dashes), so, to make entering the serial number in an email easier, the About dialog dis- plays it in a read-only . That allows the user to select the serial number, press Ctrl+C to copy it to the clipboard, and then press Ctrl+V to paste it into the email.

Many splash screens and About dialogs also contain hidden surprises, often called Easter Eggs. If you hover the mouse over a small area on the dot in the title’s exclamation point, the mouse cursor changes to a crosshair. If you click that spot, the hidden screen shown in Figure 19-3 appears. Often, this kind of hidden screen displays extra non-critical information such as the names of the developers who worked on the application.

Figure 19-3: This surprise screen displays animations of an atom and caffeine molecule.

Some hidden screens are extremely elaborate. Some play music or make the developers’ names appear in an amusing animation. I’ve even seen some that included complicated games that the user can play.

Whereas splash screens provide important information and feedback while the application is loading, hidden screens are definitely optional. They’re usually fun and easy to build, however, so developers can add them in a spare moment without much wasted effort (complicated games notwithstanding).

497 26_053416 ch19.qxd 1/2/07 6:36 PM Page 498

Part IV: Specific Techniques Displaying Splash Screens Visual Basic provides a way to automatically display a splash screen, although it’s a little awkward and not very well-documented.

First, build the form you want to use as a splash screen. Then open Solution Explorer and double-click the My Project item. On the Application , scroll to the bottom and select the form in the “Splash screen” drop-down, as shown in Figure 19-4.

Figure 19-4: Select the splash screen’s form from the drop-down list.

At this point, Visual Basic will automatically display the splash screen when the application starts. It dis- plays the form until the program’s main form has finished its startup sequence, or until a certain mini- mum amount of time has passed, whichever comes second. Unfortunately, changing the minimum amount of time or adding data loading code requires some extra work on your part.

To do either of these tasks, open Solution Explorer and double-click the My Project entry. On the Application tab, click the View Application Events button at the bottom, as shown in Figure 19-4.

To change the minimum amount of time the splash screen is displayed, add the following code to the MyApplication class to override the class’s OnInitialize method. This code sets the application’s MinimumSplashScreenDisplayTime property to 5 seconds (5,000 milliseconds) rather than its default value of 3 seconds. It then calls the base class’s OnInitialize method so that the application can resume its startup procedure as normal.

‘ Override OnInitialize to set the splash screen’s minimum display time. Protected Overrides Function OnInitialize(ByVal commandLineArgs As _

498 26_053416 ch19.qxd 1/2/07 6:36 PM Page 499

Chapter 19: Splash Screens

System.Collections.ObjectModel.ReadOnlyCollection(Of String)) As Boolean ‘ Display the splash screen for at least 3 seconds. Me.MinimumSplashScreenDisplayTime = 3000

‘ Continue initialization as usual. Return MyBase.OnInitialize(commandLineArgs) End Function

The minimum amount of time that a splash screen should be visible is a matter of preference, but 2 or 3 seconds seems to work best. If the form vanishes after less than 2 seconds, the user doesn’t really have a chance to see it. If the form sticks around for more than 5 seconds, it violates the “5-second rule” that says an interactive application should respond within 5 seconds whenever possible.

Visual Basic displays the splash screen for a minimum amount of time, or until the main form finishes its startup sequence. To get the most benefit from the splash screen, you should make the application load data, connect to databases, use Web Services to check for updates, and perform other lengthy startup actions during this time.

To perform actions while the form is starting up, open the application events module as you would to set the MinimumSplashScreenDisplayTime property. Open the code editor’s left drop-down and select “(MyApplication Events)”. Then, in the right drop-down, select the Startup event. Enter your ini- tialization code in the MyApplication_Startup event handler.

The following code shows a dummy Startup event handler. It gets a reference to the application’s splash screen form so that it can send status information to the form’s progress bar (this is described fur- ther later in this chapter). It then uses some loops to waste some time before exiting. In a real applica- tion, you would load data, connect to databases, and perform other time-consuming setup chores instead of just waiting for a few seconds.

‘ Prepare the application to run: ‘ Connect to databases, load data, etc. Private Sub MyApplication_Startup(ByVal sender As Object, _ ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) _ Handles Me.Startup Dim splash_screen As frmSplash splash_screen = DirectCast(My.Application.SplashScreen, frmSplash)

‘ Wait one second three times. For progress As Integer = 0 To 100 Step 10 ‘ Update the progress display. splash_screen.Progress = progress

‘ Wait a little while. Dim stop_time As Date = Now.AddSeconds(0.25) Do While Now < stop_time Application.DoEvents() Loop Next progress End Sub

499 26_053416 ch19.qxd 1/2/07 6:36 PM Page 500

Part IV: Specific Techniques Displaying About Dialogs Using a splash screen as an About dialog is easy. An About dialog displays most of the same information as a splash screen. In this example, the differences are that the About dialog does the following:

❑ Displays an OK button ❑ Displays a link to a support Web site ❑ Provides the hidden link to the surprise screen ❑ Does not display a progress bar

To make displaying the splash screen’s form as an About dialog easy, the form provides the ShowAbout method shown in the following code. This code makes the OK button, surprise , and Web site label visible. It hides the progress bar, and calls the form’s ShowDialog method to display the form modally.

‘ Display as an About dialog. Public Sub ShowAbout(ByVal owner As IWin32Window) btnOk.Visible = True lblSurprise.Visible = True pbarLoad.Visible = False lblUrl.Visible = True

Me.ShowDialog(owner) End Sub

The main program uses the following code to display the About dialog when the user selects the Help ’s About command:

‘ Display the About dialog. Private Sub mnuHelpAbout_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles mnuHelpAbout.Click Dim frm As New frmSplash frm.ShowAbout(Me) End Sub

Providing Feedback As the main form works through its startup chores, it provides feedback so that the splash screen can update its progress bar. Unfortunately, the main form’s startup code and the splash screen’s user inter- face run in separate threads. Code can only set a control’s property if it is running in the thread that cre- ated the control, so the main startup code cannot simply set the Value property for the splash screen’s ProgressBar control. Instead, the startup code sets the splash screen’s Progress property as shown in the section “Displaying Splash Screens” earlier in this chapter. The splash screen then updates its own ProgressBar control.

The following code shows how the splash screen handles its Progress property:

‘ Set the progress. Public Delegate Sub ShowProgressDelegate(ByVal progress As Integer) Public Sub ShowProgress(ByVal progress As Integer)

500 26_053416 ch19.qxd 1/2/07 6:36 PM Page 501

Chapter 19: Splash Screens

pbarLoad.Value = progress End Sub

‘ Get or set the . Public Property Progress() As Integer Get Return pbarLoad.Value End Get Set(ByVal value As Integer) If Me.InvokeRequired Then Dim show_progress_delegate As ShowProgressDelegate show_progress_delegate = AddressOf ShowProgress Me.Invoke(show_progress_delegate, New Object() {value}) Else ShowProgress(value) End If End Set End Property

The code starts by defining a delegate named ShowProgressDelegate to represent a subroutine that takes an integer parameter. It also defines a simple ShowProgress subroutine that sets the pbarLoad progress bar’s Value property to the routine’s integer parameter.

The form then defines the Progress property that the startup code sets to provide feedback. The Get procedure simply returns the ProgressBar’s Value property. The Set procedure calls Me.Invoke Required to see if the current code is running on a different thread than the form’s user interface thread. Me.InvokeRequired returns True if the code is running in a different thread than the form’s controls and, therefore, cannot set the control’s Value property directly.

If Me.InvokeRequired returns True, the code makes a ShowProgressDelegate, sets it equal to the form’s ShowProgress method, and uses the Invoke method to run that method, passing it the new value that the Progress property should have. This starts a call to ShowProgress on the form’s user interface thread, and that routine can set the ProgressBar control’s Value property directly.

If Me.InvokeRequired returns False, code setting the form’s Progress property is running in the user interface thread, so the code can manipulate the ProgressBar control directly. In that case, the code simply calls the ShowProgress method itself.

Calling across to the form’s user interface thread is a bit awkward, but at least the details are encapsu- lated in the form, so the main program’s call is straightforward. That code simply sets the form’s Progress property and the splash screen form handles the rest.

Controlling Item Placement The splash screen form used by this program draws several items in code. It uses code to shape the form, draw the application’s title (eJack!), and display rotated text.

To make working with these items easier, this example uses objects created at design time to determine the size and placement of the items. For example, the Panel control panTextArea determines the location of the rounded rectangle on the right in Figures 19-1 and 19-2. Similarly the lblTitle and lblUrl Label controls determine where the program’s title and Web link go. 501 26_053416 ch19.qxd 1/2/07 6:36 PM Page 502

Part IV: Specific Techniques

Not only do these controls determine the items’ placement, but they also give the items’ colors and fonts. To change the items’ positions, size, color, or font, you can change the corresponding properties of the controls at design time.

The lblTitle and lblUrl controls sit on top of the panTextArea control. When you work with the controls in the form designer, the designer tends to place the Labels inside the Panel control. That makes their X and Y position properties relative to the Panel control’s origin. However, the routines that draw these items on the form work relative to the form’s origin, not the Panel’s origin.

To make working with these controls easier, the program uses the following code to move the controls outside of the Panel control. The code first makes an array containing the controls that are inside the Panel control, and then loops through those controls. It changes each control’s parent to the form, and moves the control to account for the offset provided by the Panel. That puts the controls in their original positions, but contained inside the form and not the Panel.

‘ Move controls out of panTextArea. Dim ctls(panTextArea.Controls.Count - 1) As Control panTextArea.Controls.CopyTo(ctls, 0) For Each ctl As Control In ctls ctl.Parent = Me ctl.Left += panTextArea.Left ctl.Top += panTextArea.Top Next ctl

Now the program can use these controls to position screen elements.

Shaping Forms Making a shaped form in Visual Basic doesn’t take many steps, but it is rather confusing.

Forms have a property TransparencyKey that tells Visual Basic what color to use to make parts of the form transparent. In theory, if a pixel’s background color has this value, then Visual Basic does not draw that part of the form and lets whatever lies below the form show through. In practice, things are more confusing.

To make any of the form transparent, first set the form’s TransparencyKey and BackColor properties to the same color. If you run the program now, Visual Basic will not draw the form’s client area.

To make parts of the form visible again, make a Bitmap that contains the picture you want to display. Call the Bitmap’s MakeTransparent method to make pixels of a certain color transparent.

Now set the form’s BackgroundImage property to the Bitmap. The form will be transparent in the places where the Bitmap’s pixels are transparent.

The following code shows the pieces of the splash screen’s Load event handler that shape the form:

‘ Prepare the splash screen. Private Sub frmSplash_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ‘ Shape the form.

502 26_053416 ch19.qxd 1/2/07 6:36 PM Page 503

Chapter 19: Splash Screens

‘ Make a bitmap for our form image. Dim bm As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height) Dim gr As Graphics = Graphics.FromImage(bm)

‘ Draw smooth curves. gr.SmoothingMode = SmoothingMode.AntiAlias

‘ Make a rounded rectangle for the text area. Using rect_path As GraphicsPath = _ RoundedRectanglePath(panTextArea.Bounds(), 30, 30) ‘ Draw the text area. Using br As New SolidBrush(panTextArea.BackColor) gr.FillPath(br, rect_path) End Using Using thick_pen As New Pen(Color.DarkBlue, 3) gr.DrawPath(thick_pen, rect_path) End Using End Using

‘ Make a Bitmap containing the Jack image. Dim jack_bm As New Bitmap(My.Resources.Jack) jack_bm.MakeTransparent(bm.GetPixel(0, 0))

‘ Draw the Jack image onto the form’s Bitmap. gr.DrawImage(jack_bm, jack_bm.GetBounds(GraphicsUnit.Pixel)) ... ‘ Make black areas transparent. Me.BackColor = Color.Black Me.TransparencyKey = Me.BackColor

‘ Use the result for the form’s background image. Me.BackgroundImage = bm ... End Sub

The code starts by creating a Bitmap to fit the splash screen form. It then makes a Graphics object to draw on the Bitmap, and sets the object’s SmoothingMode property to AntiAlias to give drawn shapes smooth edges.

The code then uses a GraphicsPath object that it gets from the RoundedRectanglePath method described shortly. It uses the panTextArea Panel control to determine the size and position of the rounded rectangle. In Figures 19-1 and 19-2, the rounded rectangle is the area on the right containing the text.

The program fills the rounded rectangle with the Panel’s background color, and then outlines it in dark blue.

Next, the code loads the jack bitmap from the program’s resources and calls its MakeTransparent method to make pixels with the same color as the one in its upper-left corner transparent. It then uses the Graphics object’s DrawImage method to copy the jack image onto the Bitmap.

The code sets the form’s BackColor and TransparencyKey properties to black and sets the form’s background image to the Bitmap. The result is a form shaped to include the rounded rectangle and the jack image on the left.

503 26_053416 ch19.qxd 1/2/07 6:36 PM Page 504

Part IV: Specific Techniques

The RoundedRectanglePath function shown in the following code makes a GraphicsPath represent- ing a rounded rectangle. This code makes a GraphicsPath, and adds arcs and line segments to make the rounded rectangle:

‘ Return a GraphicsPath object representing a rounded rectangle. Public Function RoundedRectanglePath(ByVal x As Integer, ByVal y As Integer, _ ByVal wid As Integer, ByVal hgt As Integer, _ ByVal x_radius As Integer, ByVal y_radius As Integer) As GraphicsPath Dim graphics_path As New GraphicsPath graphics_path.AddArc(x, y, x_radius * 2, y_radius * 2, 180, 90) graphics_path.AddLine(x + x_radius, y, x + wid - x_radius, y) graphics_path.AddArc(x + wid - x_radius * 2, y, x_radius * 2, _ y_radius * 2, -90, 90) graphics_path.AddLine(x + wid, y + y_radius, x + wid, y + hgt - y_radius) graphics_path.AddArc(x + wid - x_radius * 2, y + hgt - y_radius * 2, _ x_radius * 2, y_radius * 2, 0, 90) graphics_path.AddLine(x + wid - x_radius, y + hgt, x + x_radius, y + hgt) graphics_path.AddArc(x, y + hgt - y_radius * 2, x_radius * 2, y_radius * 2, _ 90, 90) graphics_path.AddLine(x, y + hgt - y_radius, x, y + y_radius)

Return graphics_path End Function

Public Function RoundedRectanglePath(ByVal rect As Rectangle, _ ByVal x_radius As Integer, ByVal y_radius As Integer) As GraphicsPath Return RoundedRectanglePath(rect.X, rect.Y, rect.Width, rect.Height, _ x_radius, y_radius) End Function

The second overloaded version (the one used by the form’s shaping code) takes a Rectangle and the radii that it should use for the corner curves as parameters. It translates these values into the parameters needed by the first version of RoundedRectanglePath and calls that version.

Filling Text The following code shows how the splash screen draws filled text. It begins by creating a new GraphicsPath object.

‘ Draw “Jack!” Using jack_path As New GraphicsPath() ‘ Make a path for the text. Using string_format As New StringFormat jack_path.AddString( _ lblTitle.Text, _ lblTitle.Font.FontFamily, _ lblTitle.Font.Style, _ lblTitle.Font.Size, _ lblTitle.Bounds(), _ string_format) End Using

‘ Fill the text with a gradient. 504 26_053416 ch19.qxd 1/2/07 6:36 PM Page 505

Chapter 19: Splash Screens

Using jack_br As New LinearGradientBrush( _ jack_path.GetBounds(), Color.Red, Color.Lime, LinearGradientMode.Horizontal) Dim color_blend As New ColorBlend() color_blend.Colors = New Color() {Color.Red, Color.Yellow, Color.Lime} color_blend.Positions = New Single() {0.0, 0.5, 1.0} jack_br.InterpolationColors = color_blend

gr.FillPath(jack_br, jack_path) End Using

Using jack_pen As New Pen(Color.DarkBlue, 2) gr.DrawPath(jack_pen, jack_path) End Using End Using

The code uses the GraphicsPath object’s AddString to add a string to the path. It passes information taken from the lblTitle label control to the AddString method. This lets you easily move, resize, and change the font for the text without modifying the code.

Next, the program makes a LinearGradientBrush that shades horizontally from red to lime across the width of the text. The code defines a color blend for the brush that shades from red to yellow to lime, and then uses the Graphics object’s FillPath method to fill the text with this brush.

You could use any other brush to fill the text. For example, you could fill the text with a background color to make it hollow, or you could use a TextureBrush to fill the text with an image.

After it fills the text, the code uses the Graphics object’s DrawPath method to outline the text in dark blue.

Rotating Text When the form displays as an About dialog, it draws the program’s support Web site www.vb- helper.com on the right in a rotated font. The following code shows how the program draws this text:

‘ Draw the URL rotated over lblUrl. If lblUrl.Visible Then Const URL_TEXT As String = “www.vb-helper.com” gr.RotateTransform(90, MatrixOrder.Append) Dim url_size As SizeF = gr.MeasureString(URL_TEXT, lblUrl.Font, 1000) gr.TranslateTransform(lblUrl.Left + url_size.Height, lblUrl.Top, _ MatrixOrder.Append) gr.DrawString(URL_TEXT, lblUrl.Font, Brushes.Blue, 0, 0)

‘ Move lblUrl under the text so we can catch its Click event. lblUrl.Width = CInt(url_size.Height) lblUrl.Height = CInt(url_size.Width) lblUrl.Text = “” End If

The Graphics object provides several methods for translating, scaling, and rotating its output. The code starts by adding a rotation transformation to make the Graphics object rotate its output 90 degrees.

505 26_053416 ch19.qxd 1/2/07 6:36 PM Page 506

Part IV: Specific Techniques

Next, the code measures the string it will display. It adds a translation to make the Graphics object move text drawn at the origin onto the lblUrl Label control. Notice that the code adds the text’s height to the horizontal translation. After the text is rotated, its drawing origin is in the upper-right corner of where the text is drawn. To make the text lie above the lblUrl control, the code must move it this extra distance to the right, as shown in Figure 19-5.

Text origin Label origin Transformed text origin Some Text

Label

Figure 19-5: Text rotated 90 degrees must be translated an extra distance to make it line up over the lblUrl control.

You can use similar techniques to display text rotated at other angles, although exactly positioning the text can be even trickier than it is for text rotated 90 degrees.

The program clears the lblUrl control’s text, so it is not seen. But the control is still present, so it can display a “hand” cursor and the user can click it. The following code shows how the program displays the VB Helper Web site when the user clicks the control. When the code uses System.Diagnostics .Process to “Start” the URL, the system opens the Web site in its default browser.

‘ Open the VB Helper Web site. Private Sub lblUrl_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles lblUrl.Click System.Diagnostics.Process.Start(“http://www.vb-helper.com”) End Sub

Displaying Hidden Screens The splash screen contains a tiny Label control named lblSurprise. The control’s Text property is set to an empty string, so the user cannot see it. The control’s Cursor property is set to Cross, so it displays a crosshair cursor when the user positions the mouse over it.

When the user clicks the lblSurprise control, the following event handler displays the surprise screen modally:

‘ Display a surprise form. Private Sub lblSurprise_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles lblSurprise.Click 506 26_053416 ch19.qxd 1/2/07 6:36 PM Page 507

Chapter 19: Splash Screens

Dim frm As New frmSurprise frm.ShowDialog(Me) End Sub

The surprise form is mostly straightforward. It displays some text and an OK button that unloads the form. A PictureBox control in the lower right displays an animated GIF file showing a rotating caffeine molecule. The PictureBox animates the GIF automatically, so you don’t need to do anything except set the control’s Image property to the GIF file.

The only interesting code in the surprise form draws the animated atom in the lower left. The form con- tains a Timer control that fires its Timer event every one-tenth of a second. The following code shows how the event handler works. When the Timer event occurs, the code invalidates the picAtom PictureBox to force the control to repaint itself.

Private Sub tmrAtom_Tick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles tmrAtom.Tick picAtom.Invalidate() End Sub

Private Sub picAtom_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) Handles picAtom.Paint Const DTHETA As Double = Math.PI / 5 Static theta As Double = 0

e.Graphics.Clear(picAtom.BackColor) e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias theta += DTHETA

Const E_RADIUS As Integer = 3 Dim cx As Integer = picAtom.ClientSize.Width \ 2 Dim cy As Integer = picAtom.ClientSize.Height \ 2 Dim rx As Integer = CInt(picAtom.ClientSize.Width * 0.45) Dim ry As Integer = CInt(picAtom.ClientSize.Height * 0.15) Dim rect As New Rectangle(-rx, -ry, 2 * rx, 2 * ry) Dim x, y As Double e.Graphics.RotateTransform(60, Drawing2D.MatrixOrder.Append) e.Graphics.TranslateTransform(cx, cy, Drawing2D.MatrixOrder.Append) e.Graphics.DrawEllipse(Pens.Red, rect) x = rx * Cos(theta) y = ry * Sin(theta) e.Graphics.FillEllipse(Brushes.Red, _ CInt(x - E_RADIUS), CInt(y - E_RADIUS), _ 2 * E_RADIUS, 2 * E_RADIUS)

e.Graphics.ResetTransform() e.Graphics.RotateTransform(-60, Drawing2D.MatrixOrder.Append) e.Graphics.TranslateTransform(cx, cy, Drawing2D.MatrixOrder.Append) e.Graphics.DrawEllipse(Pens.Red, rect) x = rx * Cos(-theta * 0.9) y = ry * Sin(-theta * 0.9) e.Graphics.FillEllipse(Brushes.Green, _ CInt(x - E_RADIUS), CInt(y - E_RADIUS), _ 2 * E_RADIUS, 2 * E_RADIUS)

e.Graphics.ResetTransform() 507 26_053416 ch19.qxd 1/2/07 6:36 PM Page 508

Part IV: Specific Techniques

e.Graphics.TranslateTransform(cx, cy, Drawing2D.MatrixOrder.Append) e.Graphics.DrawEllipse(Pens.Red, rect) x = rx * Cos(theta * 0.8) y = ry * Sin(theta * 0.8) e.Graphics.FillEllipse(Brushes.Blue, _ CInt(x - E_RADIUS), CInt(y - E_RADIUS), _ 2 * E_RADIUS, 2 * E_RADIUS)

e.Graphics.ResetTransform() Const N_RADIUS As Integer = 4 e.Graphics.FillEllipse(Brushes.Black, _ cx - N_RADIUS, cy - N_RADIUS, _ 2 * N_RADIUS, 2 * N_RADIUS) End Sub

The control’s Paint event handler clears the PictureBox and sets the Graphics object’s SmoothingMode property to draw a smooth picture.

The code then calculates parameters to draw an ellipse centered at the origin. It uses the Graphics object’s RotateTransform and TranslateTransform methods to draw the ellipse rotated 60 degrees and centered in the PictureBox. It then uses some trigonometry to figure out where to draw an electron on the ellipse. The program uses a static variable to keep track of the electron’s angle around the ellipse so that it can move the electron to a new position next time the control repaints.

Next, the program resets the Graphics object’s transformation and repeats the same steps to draw a new ellipse and electron rotated –60 degrees. It multiplies the angle it used to draw the previous electron by 0.9, so this electron rotates around its ellipse at a slower speed.

The program again resets the Graphics object’s transformation and repeats the same steps to draw an ellipse and electron that is not rotated. This time, it multiplies the electron’s angle by 0.8, so this electron moves even slower than the others.

Finally, the Paint event handler draws a nucleus in the center of the PictureBox.

Summary This chapter describes some techniques you can use to make interesting and informative splash screens. Though they would be overly flashy in the body of most applications, they can add an extra dimension of interest to splash screens and About dialogs. These forms are displayed seldom enough that adding some extra sparkle won’t hurt, and it gives you a chance to show some creativity in even the most staid application.

One of the purposes of a splash screen is to let the user know that the application is working while it performs initial setup. The version described in this chapter basically gives the user something interest- ing to look at while the program gets ready to run. While the splash screen is visible, the program can connect to databases, verify network connections, check user credentials, and otherwise prepare to work.

508 26_053416 ch19.qxd 1/2/07 6:36 PM Page 509

Chapter 19: Splash Screens

Another style of splash screen also lets the user know the program is running while displaying impor- tant information at the same time. This type of screen displays a message of the day, production note, or some other piece of information that the user can read while the program initializes. The screen acts more like an About dialog, and the user closes it after reading the latest message. You can still use the techniques described in this chapter to give the screen an interesting shape, shaded or rotated text, and a link to a support , but because the user will spend more time on this type of screen, it should be a bit more conservative than the splash screen described here.

Visual Studio .NET changed the way you display splash screens. In Visual Basic 6, you needed to dis- play the splash screen yourself and use a timer to remove it after a certain period of time, or after the application had finished loading, whichever came second.

Visual Basic .NET also greatly changed the way you send output to the printer. Visual Basic 6 included a Printer object that had methods that let you draw, print text, start a new page, and perform other printing operations in a straightforward, procedural way. Visual Basic .NET uses an event-driven approach where your code must respond to requests to generate output. Chapter 20, “Printing,” describes Visual Basic .NET’s event-driven printing model, and shows how you can build your own more procedural printing system.

509 26_053416 ch19.qxd 1/2/07 6:36 PM Page 510 Programmer to Programmer TM browse books P2P forum free newsletter about wrox Get more Wrox at Wrox.com! Special Deals Free Chapter Excerpts Take advantage of special offers Be the first to preview chapters from every month the latest Wrox publications

Unlimited Access. . . Forums, Forums, Forums . . . to over 70 of our books in the Take an active role in online Wrox Reference Library. (see more discussions with fellow programmers details on-line)

Meet Wrox Authors! Read running commentaries from authors on their programming experiences and whatever else they want to talk about Browse Books

.NET XML SQL Server Visual Basic Java C#/C++

Join the community! Sign-up for our free monthly newsletter at newsletter.wrox.com