Hour 16


During this hour you will learn

Creating VB Forms

This lesson analyzes forms more thoroughly than has been done to this point. Forms support several methods and events that help you produce better programs that respond to users the way you intend.

Besides study form specifics, you'll learn more about the effects of adding multiple forms to your applications. As your application needs grow, you'll need additional forms to hold secondary data and controls. When you create the MDI forms described here, your applications will be able to support several sets of data, and your users can work with all the sets at once.

Topic 1: Working with Forms

You learned early in Part I of this course that forms have properties just as other controls have properties. Now that you've mastered a number of Visual Basic's language features, this topic section will explore more of the form properties. Also, form methods, such as the Form.Load method you saw in Hour 15, provide advanced application control that you may need.

Overview

Some programmers rarely change their application's form properties, other than the Caption property that appears at the top of the application screen. Nevertheless, you should know which properties come in handy in certain situations, because forms provide the application's backdrop, and the forms' appearance and responses can be a meaningful part of the application.

Form Properties Revisited

In earlier lessons, you learned about some form properties. For example, you learned about Caption, which determines the title in the form's title bar, and MaxButton and MinButton, which specify whether users can maximize and minimize the form during the application's execution.

You might want to display a form that users can resize at runtime. If so, you have to adjust the form's BorderStyle property. Table 16.1 describes each BorderStyle property value that you can select at design time by using code assignments. (You can't change the BorderStyle property at runtime, but you can read and use the numeric value stored in this property.)


When users resize your application's Form window during program execution, Visual Basic doesn't provide any automatic shrinkage of your form's contents. Therefore, your form's controls, if centered before users resize the form, won't remain centered because they don't automatically move when the window shrinks.

If you want full functionality and uniform appearance when users resize your form, you need to program that uniform appearance into the application. You have to work with the form's Resize event procedure to adjust all the controls and their font sizes if the Resize event takes place. Such an event procedure is a great deal of work! Most programmers either disallow resizing or let users see only part of the form's controls if they reduce the form size.

Table 16.1 BorderStyle Property Values for a Form

Value

Description

0 - None

No border appears-therefore, no control menu, title bar, or resizing window buttons appear).

1 - Fixed Single

A single line appears around the form, with the title bar and locations for resizing window buttons.

2 - Sizable

Users can resize the form window with menu commands, by dragging the form's edge, or by clicking the resizing window buttons. This is the default BorderStyle property value for forms.

3 - Fixed Dialog

The form includes a control menu and title bar but no resizing window buttons. This setting is great for dialog box forms.

4 - FixedToolWindow

This is a miniaturized form with a title bar and a Close button, sometimes used for Windows program launchers. No Windows 95 taskbar button appears for this kind of form window, making it a great style to use for toolbox windows.

5 - SizableToolWindow

This form is identical to the one FixedToolWindow creates, except that users can resize the window. It's also great for toolbox windows.

When you change a form's BorderStyle value, other property values may change automatically. For example, the ShowInTaskbar property automatically changes to False for a BorderStyle value of 4 or 5.


The WindowState property determines how the form now appears. If you select 0 - Normal, the form appears at the design-time Height, Left, Top, and Width settings that you set when you created the application. During the program, your code can check the WindowState property to see whether users now have the form minimized or maximized. If WindowState contains 1 - Minimized, users have the form minimized. If WindowState contains 2 - Maximized, users have the form maximized.

You can use WindowState to change the startup state of the form. If you set WindowState to 1 - Minimized at design time, the form will appear minimized when users first start the application. An icon will represent the minimized form if you've specified an icon file in the form's Icon property. If you set WindowState to 2 - Maximized, the form will appear maximized when users first start the application.

If you want the form to maintain a certain size at all times, just set the appropriate properties as described here. You should, however, make sure that the Movable property is set to True. (If users can't resize the form, they should be allowed to move it, because they may be running your application while working with several other windows on-screen.)

The StartupPosition property proves handy when the placement of your form is critical. Table 16.2 lists the values possible for StartupPosition. This property lets you specify a startup screen position without having to calculate screen coordinates to center the form.

Table 16.2 StartupPosition Property Values for a Form

Value

Description

0 - Manual

No specific placement

1 - CenterOwner

Center the form on its parent form

2 - CenterScreen

Center the form on-screen

3 - Windows Default

Position the form in the screen's upper-left corner

The final appearance property, Visible, is set to True or False. The default value, True, specifies that the form will appear on-screen at runtime (and all the controls residing on the form will also appear). At design time or runtime, you can change the Visible property setting to hide or display the form at appropriate times.

Don't confuse the Visible property with the Load and Unload events. A hidden form is loaded into memory but is temporarily hidden from view, so it's not visible even though it's loaded. The Visible property, however, mimics the form's Show and Hide methods. Setting a form's Visible property to True performs the same operation as executing the form's Show method, and setting a form's Visible property to False performs the same operation as executing the Hide method.

Many form properties become even more important when you create applications that contain multiple forms, as explained in the next topic section.

Important Form Events and Methods

The first event that occurs for all forms that appear in an application is the Load event. This event occurs when the runtime module loads the form into memory for display. You should place all of a form's control initialization inside the Load event.

Figure 16.1 shows the Project Properties dialog box that appears when you choose Properties from the Project menu. In most cases, you leave the form name in the Startup Object combo box. If you want the runtime module to execute a procedure before loading the initial form, however, you must add a procedure named Main to the module and select Sub Main from the Startup Object list. You can load the form from that procedure when the application is ready.

FIG. 16.1

Specify the startup form or startup procedure.

The startup form or Sub Main procedure

The Startup Options combo box becomes especially critical when you add multiple forms to the project. Visual Basic must know which form you want to appear first when users execute the application.

As mentioned earlier, the Resize event occurs whenever users resize the form to be smaller or larger. You must decide whether you want to move or resize the controls located on the form when users trigger the Resize event. Although such programming isn't a trivial task, you can create a Form_Resize () event procedure if you want to rearrange or resize some (or all) of a form's controls whenever users resize the form.

If your form's contents can't be resized due to the complexity or nature of the form, you can display a message box whenever users resize the form. This box can warn users that certain controls may be hidden after the resizing, and can mention that users need to resize the form to its original size to access those controls.


The opposite of the Load event, Unload occurs when your code contains a statement that unloads the form, such as the following:

Unload frmMyForm

More often, however, Unload takes place when users click the form window's Close button (or close the form from the window's control menu or double-clicks the form's title bar). Unlike the form's Hide method or a Visible property value of False, the Unload event completely removes the form from memory and reinitializes all controls on the form. Therefore, if your application later reloads the form with the Reload statement, all the controls are in their original state and don't remember any settings from the application's earlier load.

Lastly, the Activate and Deactivate events occur when users change which form is the active window. If your application contains only one form, the form is always active and the Activate event occurs only once-when the form first loads. If the application contains multiple forms, however, then the Deactivate event for a given form occurs whenever users leave that form window to make another form window active.

Other applications don't affect a form's Activate or Deactivate events while your Visual Basic application is running. If users switch to another program window and then return to your VB application, neither Activate nor Deactivate occurs.

If you apply the Show or SetFocus method to one of an application's forms, the previous form's Deactivate event occurs, and the new form window's Activate event occurs. Therefore, both statements trigger the Activate event procedure for the frmAccForm form:

frmAccForm.Show

frmAccForm.SetFocus ' Sets the focus to this form

Example

One of the places where form-related bugs appear in an application is at program termination. An application's execution is finished when both of the following actions occur:

A problem can occur if users (or your code) have hidden any forms during the application's execution. Users might think that the application has finished executing, although the application is still running with hidden forms.

To eliminate this problem, add an Exit command to the File menu of the application's primary form. (In every application, one form is the primary form-you'll learn more about this in the next topic section.) If your code or users trigger events that hide other forms before users exit the program from the primary form, the Exit menu command (or an exit command button added to the last form users will use) can contain code similar to the following:

Private Sub Form_Unload

Dim intI As Integer

Dim intCt As Integer

intCt = Forms.Count ' Save the count

' Loop through the forms collection and unload

' each form.

For intI = 0 To intCt - 1

Unload Forms(intI)

Next intI

End Sub

This code unloads all forms, including any that are still hidden.

When your application contains multiple forms, the application keeps track of a Forms collection that acts like the control collections you saw in previous lessons. The total number of forms in the application is returned by the Forms.Count method, and then you can loop through the forms by subscripting the Forms collection as you unload each form. When the procedure ends, you can make sure that the application has completely finished executing and that no hidden forms are left behind to trouble users later.

Next Step

Remember that you can assign form and other control property values in code at runtime. If the possible property values appear in a drop-down list in the Properties window at design time-as they do, for example, for the MousePointer property-you can assign the property either a numeric literal or its Visual Basic named literal. The following assignments for the MousePointer property are both valid:

frmMyForm.MousePointer = 1

frmMyForm.MousePointer = vbArrow

The named literal is easier to maintain later because you can tell what value you're assigning. Nevertheless, the numeric literal is easier to type when you write the program. Visual Basic's online help provides the named literals you can use. To read the online help to learn the named literals, highlight the property within the Properties window and then press F1. Figure 16.2 shows the named literals that appear on the MousePointer help page.

FIG. 16.2

The named literals are listed on the online help screens.

Named literals

Topic 2: Multiple Forms and SDI/MDI

The preceding topic section discussed applications with multiple forms. Until now, all your applications had a single form. Not much mention was made of multiform applications because, for simple applications, multiple forms are unnecessary. You now are ready to add additional forms to your applications, so you need to know how to distinguish and program SDI (Single-Document Interface) and MDI (Multiple-Document Interface) applications.

FAST TRACK
Do you already understand SDI and MDI applications? If so, skip to the next topic section, "Printing Directly to Forms".

Overview

Multiple forms generally require that you keep track of two or more sets of forms. Because you assign each form a meaningful name, your programming burden shouldn't increase too much. The form name determines which set of controls you're working with at any given time, and you can hide and show forms as needed while the application runs (or users can switch between the forms).

Even when two or more forms appear on a user's screen, only one can be active. Users can activate an inactive form by clicking any part of the form that shows from beneath the currently active form. Also, your application code can activate a form when the time is right. The frmForm.Show method activates the form window referenced by the name frmForm and hides other windows if the newly active form happens to consume more screen space than the other forms.

MDI development allows you to create very complex-looking applications. Almost all major software applications contain multiple document interfaces. As this course begins to describe more powerful programs that use files and additional controls, you'll see more need for an MDI application.

Adding Forms

When you want to add another form to your application, choose Add Form from the Project menu. Visual Basic displays the Add Form dialog box shown in Figure 16.3. You can select from several kinds of new forms to display, or you can select an existing form by clicking the Existing tab and then selecting from the list of forms.

FIG. 16.3

This is where you select the type of form to add.

If you want to add another standard form, double-click Form to have Visual Basic open the new form. Visual Basic names your subsequent forms Form2, Form3, and so on-you should assign better names as soon as you add new forms.

Hour 26, "Using Form Templates," explains how to incorporate the other kinds of forms offered in the Add Form dialog box.

VB Interface Styles

Visual Basic supports the following interface styles:

FIG. 16.4

Notepad is an SDI application because you can open only one document window at a time.

FIG. 16.5

Word is an MDI application because you can open several document windows at once.

FIG. 16.6

The Explorer-style interface always contains two window panes: a hierarchical view and a detail view.

An SDI application can have multiple forms. MDI simply means that your application might contain one or more child forms that hold data sets that are distinct from other data sets within the application. An MDI application uses a controlling form (also known as a parent form or primary form) to hold the other forms, and the other forms can't appear outside the controlling form's boundaries. If you create an SDI application-which most are-your application can have multiple forms, yet no form is considered the child of another. If your application works with only one set of data at a time (such as one customer file or one employee payroll file), or if your application doesn't work with any data except for program control information, the application should be an SDI application.

Example

If you want to create an application that works with multiple data files, you must know the MDI terminology. The primary form used as the backdrop holding the other forms is often called the parent form or parent window. The parent form acts like a form container that contains one or more child windows (also forms). In Microsoft Word, for example, the Word background with the menu bar, status bar, and toolbar is the parent window. As you open Word documents, these documents appear in child windows within the parent window, and the child windows never go outside the parent window's boundaries.

The parent window that provides boundaries for the child windows supports only these types of controls:

If users minimize any of the child windows, these windows appear minimized at the bottom of the parent window but not on the taskbar. Child windows are bound to their parent window and can't appear outside the parent window at all; the parent window defines the application's absolute boundaries.

The primary distinction of a child window form is that its MDIChild property is set to True. Also, an MDI application might contain non-child forms. For example, the application might contain an About dialog box (which users would reach by choosing About from the Help menu); this dialog box isn't an MDI child because the dialog box window doesn't hold program data.

When you want to create an MDI application, choose Add MDI Form from the Project menu and then add child window forms with an MDIChild property of True.

Next Step

Rather than build an MDI application from scratch, you can start with the Application Wizard. This wizard makes MDI applications much easier to produce than creating the forms and setting the MDIChild properties by hand.

When you create a new project and select the VB Application Wizard option, the second dialog box that appears (see Figure 16.7) lets you select the kind of interface style you prefer.

FIG. 16.7

Select the appropriate interface style from the Application Wizard.

The Application Wizard creates a project that supports the creation of multiple child windows through the File menu's New command. The following code is executed when you choose New from the File menu in the generated MDI application (the mnuFileNew.Click () event procedure executes this):

Private Sub LoadNewDoc()

Static lDocumentCount As Long

Dim frmD As frmDocument

lDocumentCount = lDocumentCount + 1

Set frmD = New frmDocument

frmD.Caption = "Document " & lDocumentCount

frmD.Show

End Sub

The code is tricky but contains nothing you can't figure out with the background you already have. The static variable named lDocumentCount is local to the procedure, yet never goes out of scope. The first time this procedure executes, lDocumentCount is 0. If the procedure changes the value of lDocumentCount (which it does by adding 1 every time the procedure executes), Visual Basic remembers the new value. Although no other procedure can access lDocumentCount, its value remains intact inside this procedure. The value doesn't go away as it would if the variable were local and automatic (the opposite of static; all variables you've declared locally so far have been automatic).

The line after that adds an interesting twist to the declaration statements you've seen before. Rather than declare a variable, this statement declares a form!

The application contains, at startup, a child form named frmDocument created at design time. This Dim statement declares a new variable named frmD to be a variable that contains the same object as frmDocument; in other words, rather than refer to an Integer or String data type, frmD refers to a document that contains the same properties as frmDocument.

After updating the static variable that keeps track of all the newly created documents, the Set statement creates a new document and sets frmD as a reference to the document. For all intents, frmD is the new document. The next statement sets the new document's caption to Document followed by the document number, and the last statement uses the Show method to display the new document on the parent window.

No matter how many times users choose New from the File menu, the LoadNewDoc() procedure is executed and creates another child window. The code for theFile menu's Close command, if you run the Application Wizard and then execute the resulting MDI application, does nothing-the Application Wizard places no code there. You have to add code that will unload the active child window when users choose Close from the File menu. As you can see, programming MDI applications can be a bit confusing.

Child forms are useful for the dialog boxes you might want to add to your applications. Although the next lesson explains how to display common dialog boxes, such as the File Print dialog box, you also can create your own dialog boxes by displaying a child form with controls that make up a dialog box. You can set the default command button with the command button's Default property and initialize text box controls with default text if you want to help users with common entries. If you set the command button's Enabled property to False, the command button can be grayed out and unavailable, depending on user action leading up to the dialog box's display.

When users need to see the dialog box, show the dialog box with the Show method this way: frmDialog.Show vbModal, Me. vbModal produces a modal dialog box that users must respond to with OK or Cancel before they can do anything else in the application. Show's second option is the name of the parent form, but you can use Me if the parent form is the standard application form.


Topic 3: Printing Directly to Forms

Until now, all your form I/O has taken place inside controls. Visual Basic offers the Print method, which you can apply to forms to print directly to the forms without using controls. Using Print to write text to forms often isn't as clean as using controls, and the form can get cluttered fast. Nevertheless, the Print method is good for titles and for testing programs as you learn Visual Basic programming.

Overview

This short topic section explains how to use the Print method so that you can write data to forms without worrying first about placing a label or text box control on the form and writing to one of those controls. Although you should use controls for most I/O, you'll be able to debug your programs more easily if you print directly to the form with Print.

The more powerful Microsoft makes the Visual Basic debugger, the less often you'll need Print. Print is handy, however, for printing lists of variables that you want to analyze.


Using the Print Method

If you want to print a line of text, Visual Basic provides the Print method for all objects that can support text. The Print method applies to forms, picture boxes, the Printer object, and the Debug object (which is a special Immediate window to which you can send test results as a program runs). The easiest of all objects to write to with the Print method is the form.

If you open a new project and double-click the Form1 window, you see the Code window. Because you've just opened the project, no objects are available to use other than Form1 and the General procedure where the Declarations section resides. All predefined procedures that the form can recognize are shown in a drop-down list box. Choose Click from the list and then type the following code between the Form_Click () procedure's opening and closing likes:

Dim strString As String

strString = "Visual Basic"

Form1.Print strString ' Print value of the string

You now can run the sample program. The form will appear and nothing will happen. Remember that you entered code into the Form_Click () subroutine-until you click the form, nothing should happen. Click the form several times. You should see results similar to those shown in Figure 16.8.

FIG. 16.8

This is simple output from the form's Print method.

Print is the one of simplest methods you can use to output information from your program to the form. To print on any form in your program, you just need to reference the form name and the Print method, separated by a period. The syntax is

frmFormName.Print DataToPrint

frmFormName is the form on which you want to print, and DataToPrint is the data you want to print. You can print literals (numeric, string, or date), variable values, or controls.

Adding Formatting to Print

You can format the Print method's output by including either the Spc() function or the Tab() function. Each works inside the Print method to add spacing to the data you're printing.

Consider the following code, which uses Spc() and the semicolon (;) to print two strings on the same line. Spc(5) tells the Print method to skip five blanks before the text string begins printing in the sixth column. If you end a Print statement with a semicolon, the next Print prints where the current one left off rather than print on the next line, as would happen without the semicolon.

Private Sub Form_Click ()

Dim strString As String

strString = "Visual Basic"

Form1.Print "*"; Spc(5); strString; ' Notice semicolon.

Form1.Print Spc(2); strString

End Sub

The output will appear on the form like this as you click the form several times to trigger the code:

* Visual Basic Visual Basic

* Visual Basic Visual Basic

* Visual Basic Visual Basic

The code forces the Print method to skip 5 spaces before the first Visual Basic appears. After two more spaces, the second Print also prints Visual Basic. The next time you click, you force the event procedure to execute again, repeating the process.

If you use Tab() instead of Spc(), Visual Basic moves to the column argument located inside the parentheses and prints the next data item there. Spc() forces the next print to begin a certain number of spaces over, whereas Tab() forces the next print to begin in a specific column. Consider the following code:

Private Sub Form_Click()

Dim strString As String

strString = "Visual Basic"

Form1.Print "*"; Tab(5); strString; Tab(20); strString

Form1.Print "*"; Spc(5); strString; Spc(20); strString

End Sub

Tab() keeps the printing in specific columns, but Spc() moves the printing over by a certain number of spaces.

Here is the output from this procedure:

* Visual Basic Visual Basic

* Visual Basic Visual Basic

Example

You can use the Print method to print blank lines on a form by not specifying any data. Consider this code:

Private Sub Form_Click()

Dim strString As String

Dim CurLine As Integer

CurLine = 1

strString = "Visual Basic"

Form1.Print strString & " is on Line #" & CurLine

For CurLine = 2 To 6

Form1.Print ' Print blank lines!

Next CurLine

Form1.Print strString & " is on Line #" & CurLine

End Sub

The output contains five blank lines between the lines printed:

Visual Basic is on Line 1

Visual Basic is on Line 7

Next Step

By experimenting with the different keywords available to the Print method, you can place information on a form to inform your users or alert them when something significant happens.

Visual Basic supports several other properties that can be used to place text onto a form. These properties use the current position of the text cursor, which Visual Basic moves as the Print method executes. Information containing the location of the cursor is stored in the CurrentX and CurrentY properties. These properties let you determine exactly where you want your output to appear.

Another property, ScaleMode, affects how CurrentX and CurrentY behave. A form can recognize several different modes depending on the ScaleMode property you set. This mode refers to the scale used for drawing graphics and text on the form.

The most common ScaleMode property for text is character mode. This means that when CurrentX and CurrentY are both set to 5, the next Print method will begin at column 5, row 5. The starting position of the ScaleMode property is the upper-left corner of the form (with the coordinates O,O). The following example Click event procedure uses the ScaleMode, CurrentX, and CurrentY properties:

Private Sub Form_Click()

' Set up for characters

Form1.ScaleMode = vbCharacters ' Character (4)

Form1.CurrentX = 20 ' Move across 20 chars

Form1.CurrentY = 6 ' Move down 6 lines

Form1.Print "Down and across"

Form1.CurrentX = 0 ' Move back to the left

Form1.CurrentY = 0 ' Move back up

Form1.Print "Upper left"

End Sub

Study the output in Figure 16.9. Notice that the output of the second Print method appears higher on the form than the first Print method's output due to the coordinate placement.

FIG. 16.9

Use CurrentX and CurrentY to position the Print method's text cursor.

Summary

Form properties, methods, and events all work together to serve as the foundation for your application. The form is the backdrop for the entire application, and Visual Basic supports several properties and methods that display the form in the manner you want. You can control exactly how much ability users have to change and resize the form.

Visual Basic supports three interface styles: SDI, MDI, and Explorer-style. Most of your programs will use SDI style unless you want users to be able to work with multiple sets of data within the same application. (Such an application lets users cut and paste between data files easily.)

The final topic section taught you how to use the Print method to send output directly to the form. Print is one of the oldest elements of the Visual Basic language, because it has been around since the original BASIC from decades ago. Unlike the original PRINT command, however, Visual Basic's Print is a method that applies to objects such as forms.

In Hour 17 you'll learn how to add dialog boxes to your application so that users can specify options and values required by the application to complete its tasks.

Hour 16 Quiz

  1. How can you keep users from resizing a form?
  2. How can you keep users from moving a form?
  3. What's the easiest way to place a form in the center of the screen when your application first starts?
  4. What's the difference between the Activate and Load form events?
  5. What's the difference between SDI and MDI applications?
  6. True or false: An SDI application can contain, at most, one form.
  7. Name the three interface styles that the Application Wizard can create.
  8. What method sends output directly to a form?
  9. What's the difference between Spc() and Tab()?
  10. What is the output from the following Print methods?

Form1.Print "Line 1";

Form1.Print "Line 2"

Hour 16 Homework Exercises

  1. Run the Application Wizard to generate an MDI application.
  2. Run the Application Wizard to generate an Explorer-style application.
  3. Create code to write the numbers from 1 to 100 on a form. Separate the numbers with one space. Don't use any controls for the output. Trigger the output in the form's Click event procedure.


© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.