Chapter 9. Creating and Displaying New Forms

So far, this book has dealt mostly with building forms. Previous lessons explained how to add, arrange, and handle the events of controls on a single form.

In this lesson you learn how to display multiple forms in a single program. You learn how to add new forms to the project and how to display one or more instances of those forms. Once you've mastered these techniques, you can make programs that display any number of forms for all kinds of different purposes.

ADDING NEW FORMS

To add a new form to a project, open the IDE's Project menu and select Add Windows Form. Leave the Windows Form template selected, enter a descriptive name for the new type of form, and click Add. After you click Add, Visual Studio adds the new form type to the project. Figure 9-1 shows the new form in Solution Explorer.

FIGURE 9-1

Figure 9.1. FIGURE 9-1

Now you can add Labels, TextBoxes, Buttons, MenuStrips, and any other controls you want to the new form.

Note

Remember that to open a form in the Form Designer, double-click it in Solution Explorer.

UNDERSTANDING CLASSES AND INSTANCES

When you add a new form to the project, you're really adding a new type of form, not a new instance of that type. If you add the MakeUserForm type to a project and then run the program, you still see only the original startup form (with the catchy name Form1), and MakeUserForm is nowhere to be seen.

Form types such as Form1 and MakeUserForm are examples of classes. A class is like a blueprint for making items based on that class. The items themselves are called instances of the class. These are important and sometimes confusing topics so I'm going to explain them briefly now and then explain them again in greater detail later in the book in the lessons in Section IV.

A class defines the characteristics of any objects from that class. Your code can use the New keyword to create objects of the class. Once you define the class, you can make as many copies (instances) as you like, and every copy is identical in structure to all the others. Different instances may have different property values but their overall features are the same.

For example, suppose you define a MakeUserForm that has FirstName, LastName, Street, City, State, and ZIP labels and textboxes. Now suppose your program displays two instances of this class. Both of the forms will have the same labels and textboxes, so they have basically the same structure. However, the user can type different values into the two forms.

Your code can also change different instances in various ways. For example, menu items, buttons, and other controls could invoke event handlers that modify the form: change its colors, move controls around, resize the form, or whatever. Here's one of the more potentially confusing features of classes: The code in the event handlers modifies only the form that is currently running the code.

For example, suppose you build a form that has three Buttons that change the form's BackColor property to red, green, and blue, and then you display three instances of the form. When the user clicks the first form's Red button, the event handler makes the first form red but the other forms are unchanged. The code in the event handler is running in the first form's instance so that's the only instance of the form it affects.

Hopefully, by now you think I've beaten this topic into the ground and you understand the difference between the class (MakeUserForm) and the instance (a copy of MakeUserForm visible on the screen). If so, you're ready to learn how to actually display forms.

DISPLAYING FORMS

The New keyword creates a new instance of a form (or other class). If you want to do anything useful with the form, your code needs a way to refer to the instance it just created. It can do that with a variable. I'm jumping the gun a bit by discussing variables (they're covered in detail in Lesson 11) but, as was the case when I introduced the If statement in Lesson 8, this particular use of the concept is very useful and not too confusing, so I only feel a little guilty about discussing it now.

To declare a variable to refer to a form instance, you use the Dim keyword, followed by the name that you want to give the variable, the As keyword, and the variable's data type, which in this case is the form's type. For example, the following code declares a variable named frmMakeUser of type MakeUserForm:

Dim frmMakeUser As MakeUserForm

At this point, the program has a variable that could refer to a MakeUserForm object but right now it doesn't refer to anything. The variable contains the special value Nothing, which basically means it refers to no object.

To make the variable refer to a form instance, the code uses the New keyword to create the instance and then sets the variable equal to the result. For example, the following code creates a new MakeNewUser form and makes the frmMakeUser variable point to it:

frmMakeUser = New MakeUserForm()

Now the variable refers to the new form. The final step is to display that form. You can do that by calling the new form's ShowDialog or Show method.

Note

Technically, the variable doesn't hold or contain the form. Instead it contains a reference to the form. The reference is like an address that points to where the form actually resides in memory. When your code says something like frmMakeUser.Show(), it hunts down the actual form instance and invokes its Show method.

For now the distinction is small and you don't need to worry too much about it, but later it will be useful to know that some variables are value types that actually hold their values (Integer, Long, Double) and some are reference types that hold references to their values (object references and, interestingly, String).Lesson 17 says a bit more about this when it discusses structures.

The ShowDialog method displays the form modally. That means the form appears on top of the program's other forms and the user cannot interact with the other forms until this form closes.

This is the way dialogs normally work. For example, when you open the IDE's Project menu and select Add Windows Form, the Add New Item dialog displays modally so you cannot interact with other parts of the IDE (the Properties window, Solution Explorer, the menus) until you close the dialog by clicking Add or Cancel.

The following code displays the form referred to by the variable frmMakeUser modally:

frmMakeUser.ShowDialog()

The Show method displays the form nonmodally. That means the form appears and the user can interact with it or with the program's other forms.

The following code displays the form referred to by the variable frmMakeUser nonmodally:

frmMakeUser.Show()

Visual Basic allows two other syntaxes for defining and instantiating objects. First, you can declare and initialize the object all in one line as in the following code:

Dim frmMakeUser As MakeUserForm = New MakeUserForm()

You can use similar code to declare and initialize other kinds of variables, too.

The final syntax for defining and instantiating an object declares the variable as a new instance of the class as in the following code:

Dim frmMakeUser As New MakeUserForm()

These two versions are concise, easy to understand, and keep the definition of the variable close to where it is initialized. Contrast this with the case where the code declares a variable and initializes it much later. At that point, you may not remember how the variable was declared.

Because of these considerations, the last syntax is preferred by most developers.

The UserForms example program shown in Figure 9-2 (and available as part of this lesson's code download at www.wrox.com or www.vb-helper.com/24hourvb.html) displays a main form with a New User button. Each time you click the button, the program displays a new MakeUserForm. In Figure 9-2, you can see the main form and two MakeUserForms.

FIGURE 9-2

Figure 9.2. FIGURE 9-2

The following code shows how the UserForms program displays a new MakeUserForm when you click its button. The code declares and initializes a new form and displays it nonmodally.

' Make and display a new MakeUserForm.
Private Sub btnNewUser_Click() Handles btnNewUser.Click
    Dim frmMakeUser As New MakeUserForm()
    frmMakeUser.Show()
End Sub

Each time you click the button, the event handler executes again. Each time it runs, the event handler creates a new version of the variable named frmMakeUser, makes a new instance of the MakeUserForm, and displays that instance; so each time you click the button, you get a new form.

CONTROLLING REMOTE FORMS

When you create a new form and make a variable to refer to it, you can later use that variable to manipulate the form. There's just one catch: the techniques described so far don't keep the new form variable around long enough to be useful.

For example, the following code creates and displays a new form:

' Make and display a new MakeUserForm.
Private Sub btnNewUser_Click() Handles btnNewUser.Click
    Dim frmMakeUser As New MakeUserForm()
    frmMakeUser.Show()
End Sub

When the code finishes executing the event handler, the event handler stops running. If the user clicks the button again, the event handler springs back into action.

Unfortunately, when the event handler stops running, it loses its grip on the frmMakeUser variable. The next time the event handler runs, it creates a new variable named frmMakeUser and works with that one.

This is bad for a program that wants to manipulate the new form later. Because the variable is gone, it cannot refer to it to manipulate the form.

The good news is that this is fairly easy to fix. If you move the variable's declaration out of the event handler, the variable exists throughout the program's lifetime. The event handler can make the variable point to a new form, and it can then use the variable later to manipulate that form.

The following code demonstrates this technique. The main form's Load event handler creates and displays a new ColorForm. When the user clicks the main form's Red button, its event handler changes the remote form's BackColor and ForeColor properties. The startup form also contains green and blue buttons that have similar event handlers.

' The remote form we will manipulate.
Dim frmRemoteColor As ColorForm
' Make the new ColorForm and display it.
Private Sub Form1_Load() Handles MyBase.Load
    frmRemoteColor = New ColorForm()
    frmRemoteColor.Show()
End Sub

' Set the ColorForm's colors.
Private Sub btnRed_Click() Handles btnRed.Click
    frmRemoteColor.BackColor = Color.Red
    frmRemoteColor.ForeColor = Color.Pink
    frmRemoteColor.lblMessage.Text = "I'm red!"
End Sub

Here the frmRemoteColor variable is declared outside of the event handlers. The form's Load event handler initializes the variable and displays the remote form. The btnRed_Click event handler uses it. Because the variable is declared outside of the event handlers, they can all use it. (Lesson 13 has more to say about when and where variables are available to the code.)

Note

Just as you can declare and initialize a variable in a single statement inside an event handler, you can do the same outside of an event handler. In that case, the program's Load event handler doesn't need to initialize the variable, although the program still needs the event handler to display the new form.

The following code shows the new version of the preceding code.

' Declare and initialize the remote form we will manipulate.
Dim frmRemoteColor As New ColorForm()

' Display the ColorForm.
Private Sub Form1_Load() Handles MyBase.Load
    frmRemoteColor.Show()
End Sub

' Set the ColorForm's colors.
Private Sub btnRed_Click() Handles btnRed.Click
    frmRemoteColor.BackColor = Color.Red
    frmRemoteColor.ForeColor = Color.Pink
    frmRemoteColor.lblMessage.Text = "I'm red!"
End Sub

The RemoteForm example program shown in Figure 9-3 (and available as part of this lesson's code download at www.wrox.com or www.vb-helper.com/24hourvb.html) uses similar code to make its ColorForm red, green, or blue.

FIGURE 9-3

Figure 9.3. FIGURE 9-3

In addition to modifying a remote form's properties, you can change the properties of the controls on that form. You refer to a control by using the form variable, followed by a dot, followed by the control's name.

For example, the bold line in the following code accesses the form referred to by the frmRemoteColor variable. It locates that form's lblMessage control and changes its Text property to "I'm red!"

' Set the ColorForm's colors.
Private Sub btnRed_Click() Handles btnRed.Click
    frmRemoteColor.BackColor = Color.Red
    frmRemoteColor.ForeColor = Color.Pink
    frmRemoteColor.lblMessage.Text = "I'm red!"
End Sub

Note

Allowing one form direct access to a second form's controls is considered bad practice by some developers because it potentially lets the first form mess up the contents of the second. In technical terms, this weakens the second form's encapsulation, its ability to hide its internal details from the outside world.

A more restrictive approach would be to add a public SetCaption procedure to the ColorForm. Then other code would call that procedure instead of setting the label's text directly. You learn how to build procedures such as this one in Lesson 20.

TRY IT

In this Try It, you create an application similar to the one shown in Figure 9-4. When the user clicks the main form's buttons, the program displays the other forms nonmodally.

Note

You can download the code and resources for this Try It from the book's web page at www.wrox.com or www.vb-helper.com/24hourvb.html. You can find them in the Lesson09 folder in the download.

FIGURE 9-4

Figure 9.4. FIGURE 9-4

Lesson Requirements

In this lesson:

  • Create the forms shown in Figure 9-4.

  • Declare and initialize the form variables outside of any event handler.

  • Add code to the main form's Button event handlers to display the corresponding secondary forms nonmodally.

Hints

  • Normally every form appears in the taskbar. To avoid cluttering the taskbar with all the secondary forms, set their ShowInTaskbar properties to False.

Step-by-Step

  • Create the forms shown in Figure 9-4.

    1. Create the main form as shown in Figure 9-4.

    2. Create the GettingThereForm.

      1. Open the Project menu and select Add Windows Form. Enter the form type name GettingThereForm and click Add.

      2. Set the form's ShowInTaskbar property to False.

      3. Add the Label, ListBox, and Buttons as shown in Figure 9-4. Set the Anchor properties appropriately.

    3. Repeat step 2 to create the GettingAroundForm.

    4. Repeat step 2 to create the LodgingForm.

    5. Repeat step 2 to create the FunStuffForm.

  • Declare and initialize the form variables outside of any event handler.

    1. Add the following to the main form's code module outside of any event handlers:

      ' Declare and initialize the forms but don't display them.
      Dim frmGettingThere As New GettingThereForm()
      Dim frmGettingAround As New GettingAroundForm()
      Dim frmLodging As New LodgingForm()
      Dim frmFunStuff As New FunStuffForm()
  • Add code to the main form's Button event handlers to display the corresponding secondary forms nonmodally.

    1. Use code similar to the following:

      ' Display the getting there form.
      Private Sub gettingThereButton_Click() Handles btnGettingThere.Click
          frmGettingThere.Show()
      End Sub
      
      ' Display the getting around form.
      Private Sub gettingAroundButton_Click() Handles btnGettingAround.Click
          frmGettingAround.Show()
      End Sub
      
      ' Display the lodging form.
      Private Sub lodgingButton_Click() Handles btnLodging.Click
          frmLodging.Show()
      End Sub
      
      ' Display the fun stuff form.
      Private Sub funStuffButton_Click() Handles btnFunStuff.Click
          frmFunStuff.Show()
      End Sub

Note

Please select Lesson 9 on the DVD to view the video that accompanies this lesson.

EXERCISES

  1. Make a program that displays a Button that says "New Form." When the user clicks the Button, display a new nonmodal instance of the same kind of form. (What happens when you click the new form's button? What happens if you close the new form? What happens if you make several forms and close the original one?)

  2. Copy the program you made for Exercise 1 and add a TextBox named txtValue to the form. Before you display the new form, copy the main form's TextBox value into the new form's TextBox.

  3. Make a program that displays a TextBox and a "New Form" Button. When the user clicks the Button, display a new form of type MessageForm modally.

    Give the MessageForm two Labels. Make the first Label say "You entered" and leave the second Label blank. When the main program displays the MessageForm, it should copy whatever is in its TextBox into the MessageForm's second label.

  4. Build the PickAPicture program shown in Figure 9-5. When the user clicks one of the thumbnail images on the main form, the program should display a PictureForm showing the image at full scale. Use whatever images you like. (Hints: Display the thumbnail images in PictureBoxes with ScaleMode set to Zoom. Set the PictureForm's BackgroundImage property equal to the PictureBox's Image value.)

    FIGURE 9-5

    Figure 9.5. FIGURE 9-5

  5. Extra Credit: As I've mentioned before, redundant code is usually a sign that the program's structure can be improved. The PickAPicture program from Exercise 4 uses four practically identical event handlers. The only difference is the image that they assign to the PictureForm's background.

You can improve this program by making all four PictureBoxes use the same event handler and making the event handler figure out which image to use.

The event handler's sender parameter is the control that raised the event — in this case, the PictureBox that the user clicked. The data type of that parameter is Object, but you can get a variable of type PictureBox that refers to the same object by using the DirectCast statement. DirectCast takes two parameters: an object and the type into which you want to convert that object. In this example, it takes an Object that happens to refer to a PictureBox and returns a PictureBox variable referring to the same object. The following code shows how you can get a variable that treats the sender parameter as a PictureBox:

Dim pic As PictureBox = DirectCast(sender, PictureBox)

Of course you cannot use the sender parameter if you use relaxed delegates to remove it, so don't.

Copy the program you built for Exercise 4. Modify the first event handler so it uses DirectCast to get a reference to the PictureBox that the user clicked, and then uses that PictureBox to set the PictureForm's background. Delete the other event handlers and make all the PictureBoxes share the modified one. Rename the event handler to Picture_Click so its name doesn't imply that it only handles the first PictureBox's Click event.

Note

You can find solutions to this lesson's exercises in the Lesson09 folder inside the download available on the book's web site at www.wrox.com or www.vb-helper.com/24hourvb.html.

FIGURE 9-5
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset