Training
Certifications
Books
Special Offers
Community




 
Programming Microsoft® Windows® with Microsoft Visual Basic® .NET (Core Reference)
Author Charles Petzold
Pages 1344
Disk N/A
Level All Levels
Published 07/31/2002
ISBN 9780735617995
ISBN-10 0-7356-1799-6
Price(USD) $59.99
To see this book's discounted price, select a reseller below.
 

More Information

About the Book
Table of Contents
Sample Chapter
Index
Companion Content
Related Series
Related Books
About the Author

Support: Book & CD

Rate this book
Barnes Noble Amazon Quantum Books

 


Chapter 2: Hello, Windows Forms continued


Variations on a Theme

Let's try creating two forms to get a better feel for this process.

TwoForms.vb

'-----------------------------------------
' TwoForms.vb (c) 2002 by Charles Petzold
'-----------------------------------------
Imports System.Windows.Forms
 
Module TwoForms
    Sub Main()
        Dim frm1 As New Form()
        Dim frm2 As New Form()
 
        frm1.Text = "Form passed to Run()"
        frm2.Text = "Second frm"
        frm2.Show()
 
        Application.Run(frm1)
 
        MessageBox.Show("Application.Run() has returned  " & _
                        "control back to Main. Bye, bye !", _
                        "TwoForms")
    End Sub
End Module

This program creates two forms, named frm1 and frm2, and gives them two different caption texts so that you can tell them apart. The Show method is called for frm2, and frm1 is passed to Application.Run. A message box indicates when Application.Run returns control back to Main.

You may want to run TwoForms a couple times to see what's going on. If you close frm2 first, frm1 is unaffected. The only way you can get Application.Run to return and the program to display its message box is to also close frm1. If you close frm1 first, however, both forms disappear from the screen, Application.Run returns control to Main, and the message box is displayed.

So that's something else that Application.Run does: when you close the form passed as an argument to Application.Run, the method closes all the other forms created by the program. If you don't pass a Form object to Application.Run (as RunFormBadly demonstrated), the program needs to explicitly call the Application.Exit method to force Application.Run to return. But where can the program call Application.Exit if it's off somewhere in the Application.Run call? We'll see shortly how a program can set events that return control to a program and potentially give it the opportunity to call Application.Exit if it needs to.

Form Properties

Like many other classes, the Form class defines a number of properties, and Form also inherits additional properties from its ancestors, particularly Control. Two such properties that I've already described are Text and Visible. Here's a program that sets a smattering of sample properties to illustrate some of the flexibility you have in creating and displaying a form.

FormProperties.vb

'-----------------------------------------------
' FormProperties.vb (c) 2002 by Charles Petzold
'-----------------------------------------------
Imports System.Drawing
Imports System.Windows.Forms
 
Module FormProperties
    Sub Main()
        Dim frm As New Form()
 
        frm.Text = "Form Properties"
        frm.BackColor = Color.BlanchedAlmond
        frm.Width *= 2
        frm.Height \= 2
        frm.FormBorderStyle = FormBorderStyle.FixedSing le
        frm.MaximizeBox = False
        frm.Cursor = Cursors.Hand
        frm.StartPosition = FormStartPosition.CenterScr een
 
        Application.Run(frm)
    End Sub
End Module

BackColor is the property that determines the background color of the form. As you'll see in the next chapter, Color is a structure defined in the System.Drawing namespace (notice the Imports statement) that contains 141 properties that are actually color names. These names are listed on the inside back cover of this book.

The Width and Height properties determine the initial dimensions of the form. The two statements that change these properties perform both Get and Set operations, effectively doubling the width of the window and halving its height from the default values.

FormBorderStyle is an enumeration that defines not just the appearance and functionality of the form's border but other aspects of the form as well. Here are the possible values:

FormBorderStyle Enumeration

MemberValueComments
None0No border, no caption bar
FixedSingle1Same as FixedDialog
Fixed3D2Chiseled look
FixedDialog3Preferred for dialog boxes
Sizable4Default
FixedToolWindow5Smaller caption bar, no control box
SizableToolWindow6Same as FixedToolWindow but with sizing border

The default FormBorderStyle.Sizable style results in a form that has a caption bar with a control box on the left, followed by the caption bar text; and a minimize box, a maximize box, and a close box at the right. A tool window has a shorter caption bar, no control box, no minimize box, and no maximize box.

The FormBorderStyle.FixedSingle style I've used in this program prevents the user from resizing the form. In addition, I've set the MaximizeBox property to False, so the maximize box is disabled, as shown here:

Click to view graphic
Click to view graphic

The Cursor property indicates what the mouse cursor looks like when it's moved to the client area of the form. The StartPosition property indicates where the form is initially displayed; the FormStartPosition enumeration value CenterScreen directs the form to appear in the center of the screen rather than in a default position determined by Windows.

As you look at the FormProperties program, you might start to be puzzled about how real-life Windows Forms programs are structured. It seems like you need to call Application.Run to get the form to interact with the user, but Application.Run doesn't return until the form is closed.

In short, there doesn't seem to be any place to put your code!

Event-Driven Input

Many console programs don't interact with a user at all. A typical console application obtains all the information it needs from command-line arguments, does its stuff, and then terminates. If a console program needs to interact with a user, it gets input from the keyboard. In the .NET Framework, a console program reads keyboard input by calling the Read or ReadLine methods of the Console class. After the program pauses to get keyboard input, it then continues on its way.

Programs written for graphical environments, however, have a different input model. One reason for this is the existence of multiple input devices. Programs get interactive input not only from the keyboard but also from the mouse. In addition, programs can create controls—such as buttons, menus, and scroll bars—that also interact with the user on behalf of the main program.

In theory, I suppose, a programming environment that supported multiple input devices could handle everything using the technique of serial polling. In serial polling, the program checks for input from the keyboard, and if there is none, checks the mouse; if there's none there, it checks for input from the menu, and the menu checks for input from the keyboard and the mouse, and so forth. (Prior to the advent of Windows, character-mode PC programs that used mouse input generally implemented serial polling.)

It turns out, however, that a better input model for multiple input devices is the event-driven model. As implemented in Windows Forms, each type of input is associated with a different method in your program. When a particular input event occurs (such as a key on the keyboard being pressed, the mouse being moved, or an item being selected from the program's menu), the appropriate method is called, seemingly from outside the program.

At first, this input model sounds chaotic. As the user is typing away and moving the mouse, pressing buttons, scrolling scroll bars, and picking menu selections, the program must get bombarded with method calls coming from all different directions. Yet in practice, it's much more orderly than it sounds because all the methods exist in the same execution thread. Events never interrupt a program's execution. Only when one method finishes processing its event is another method called with another event.

Indeed, after a Windows Forms program performs initialization on its form, everything that the program does—every little piece of code it executes—is in response to an event. For much of the time, the program is sitting dormant, somewhere deep inside the Application.Run call, waiting for an event to happen. Indeed, it's often helpful to think of your Windows Forms programs as state machines whose state is determined entirely by changes initiated by events.

Events are so important that they are woven into the very fabric of the .NET Framework and Visual Basic .NET. Events are members of classes along with constructors, fields, methods, and properties. When a program defines a method to process an event, the method is called an event handler. The arguments of the handler match a function prototype definition called a delegate. We'll see how this all works shortly.

As you'll discover in Chapter 6, there are three different types of keyboard events. One type of event tells you when a key is pressed and another when the key is released. A third keyboard event tells you when a character code has been generated by a particular combination of keystrokes.

In Chapter 8, I'll introduce the seven types of mouse events, indicating when the mouse has moved and what buttons have been clicked or double-clicked.

In Chapter 10, you'll see that there's also a timer event. This event periodically notifies your form when a preset length of time has elapsed. Clock programs use timer events to update the time every second.

In Chapter 12, when we start creating controls (such as buttons and text boxes and list boxes) and putting them on the surface of forms, you'll find out that these controls communicate information back to the form with events. Events indicate when the button has been clicked or the text in the text box has changed.

In Chapter 14, you'll discover that menus also communicate information to a form using events. There's an event to indicate when a drop-down menu is about to be displayed, an event to indicate when a menu item is selected, and an event to indicate when a menu item is clicked.

But one of the oddest events—perhaps the most unlikely candidate for eventhood—is also one of the most important. This event, known as the Paint event, tells your program when you need to display output on your window.

Nothing reveals the enormous difference between command-line programs and graphical programs more than the Paint event. A command-line program displays output whenever it feels like it. A Windows Forms program can display output whenever it wants to as well, but doing so isn't quite adequate. What the Paint event is really doing is informing a program when part or all of the form's client area is invalid and must be redrawn.

How does a client area become invalid? When a form is first created, the entire client area is invalid because the program hasn't yet drawn anything. The first Paint event that a program receives tells the program to draw something on the client area.

When you move windows around the screen so that they overlap, Windows doesn't save the appearance of a client area that is covered by another window. When that client area is later uncovered, the program must restore its appearance. For that reason, it gets another Paint event. When you restore a program that's been minimized, you get another Paint event.

A Windows program must be able to entirely repaint its client area at any time. It must retain—or keep quickly accessible—all the information it needs to do this. Structuring your programs to respond properly to Paint events may sound quite restrictive, but you'll get the hang of it.

Handling the Paint Event

The subject of events is best approached with examples. In practical terms, handling a Paint event in your program first involves taking a look at PaintEventHandler, a delegate that is defined in the System.Windows.Forms namespace with a single statement that (in Visual Basic syntax) looks something like this:

Public Delegate Sub PaintEventHandler(ByVal obj As Obje ct, _
                                      ByVal pea As Pain tEventArgs)

If this statement looks like a function prototype to you, you're not too far from the mark. The second argument indicates a class named PaintEventArgs—also defined in the System.Windows.Forms namespace—that I'll discuss shortly.

To handle Paint events in one of the programs shown earlier in this chapter, you must define a method in your module that has the same arguments and return type as the PaintEventHandler delegate:

Sub MyPaintHandler(ByVal obj As Object, ByVal pea As Pa intEventArgs)
 
End Sub

You then attach this event handler to the Paint event of the Form object using the Visual Basic AddHandler statement

AddHandler frm.Paint, New PaintEventHandler(AddressOf M yPaintHandler)

or the simpler syntax that I'll be using in this book:

AddHandler frm.Paint, AddressOf MyPaintHandler

Paint is an event defined in the Control class and is part of the Form class by virtue of inheritance. The only two operations you can perform on the Paint event involve the AddHandler and RemoveHandler statements. The AddHandler statement installs an event handler by attaching a method to an event. The general syntax is

AddHandler object.event, AddressOf method

You detach a method from an event by using the same general syntax but with RemoveHandler:

RemoveHandler object.event, AddressOf method

Detaching a method from an event is rarely necessary, however. Generally, you'll install an event handler and never uninstall it.

The two arguments to the Paint event handler are an object I've called obj and a PaintEventArgs class I've abbreviated as pea. The first argument refers to the object that this Paint event applies to, in this case, the object frm. The object is sometimes called a "sender" because the event originates from that object.

The PaintEventArgs class is defined in the System.Windows.Forms namespace, and it has two properties, Graphics and ClipRectangle, which are both read-only:

PaintEventArgs Properties

PropertyTypeAccessibilityDescription
GraphicsGraphicsGetAll-important graphics output object
ClipRectangleRectangleGetInvalid rectangle

The Graphics property contains an instantiation of the Graphics class, which is defined in the System.Drawing namespace. Graphics is an extremely important class in the Windows Forms library, ranking right up there with Form. This is the class you use to draw graphics and text on your form. The System.Drawing namespace implements a graphics programming system known as GDI+, which is an enhanced version of the Windows Graphics Device Interface. I'll discuss the ClipRectangle property in Chapter 4.

In a vast majority of the programs in this book, you'll see

Dim grfx As Graphics = pea.Graphics

as the first line in the Paint event handler. You can name your Graphics object whatever you want. This object shows up so much in graphics code that some programmers use just the letter g for it! I've taken a more moderate approach.

Before all this new stuff piles up too deeply, let's take a look at an actual program that implements a Paint event handler.

PaintEvent.vb

'-------------------------------------------
' PaintEvent.vb (c) 2002 by Charles Petzold
'-------------------------------------------
Imports System
Imports System.Drawing
Imports System.Windows.Forms
 
Module PaintEvent
    Sub Main()
        Dim frm As New Form()
        frm.Text = "Paint Event"
        AddHandler frm.Paint, AddressOf MyPaintHandler
 
        Application.Run(frm)
    End Sub
 
    Sub MyPaintHandler(ByVal obj As Object, ByVal pea A s PaintEventArgs)
        Dim grfx As Graphics = pea.Graphics
        grfx.Clear(Color.Chocolate)
    End Sub
End Module

After the form is created in Main, the method named MyPaintHandler is attached to the Paint event of the form. In this handler, the program obtains a Graphics object from the PaintEventArgs class and uses that to call the method Clear. Clear is a simple method—perhaps the simplest drawing method—defined in the Graphics class:

Graphics Methods (selection)

MethodDescription
Sub Clear(ByVal clr As Color)Paints entire client area with color

The argument is an object of type Color, which I'll discuss in much more detail in the next chapter. As I mentioned in connection with the FormProperties program shown earlier in this chapter, the easiest way to get a color is to specify one of the 141 color names implemented as shared properties in the Color structure.

To get an idea of the frequency with which the program gets Paint events, try inserting the statement

Console.WriteLine("Paint Event")

in MyPaintHandler. A couple programs in the next chapter will also visually demonstrate the frequency of Paint events.

From here on, all the Windows Forms programs in this book will have at least the following three Imports statements at the top of the program:

Imports System
Imports System.Drawing
Imports System.Windows.Forms

Generally, these are the minimum required for any nontrivial Windows Forms application.

You might see a connection between these three Imports statements and the three DLLs that you need to specify as references when compiling the program. They're certainly related but they're not precisely the same. The Imports statements are somewhat similar to the With statement in Visual Basic. They exist solely so that you don't have to type fully qualified class names. The DLLs specified as references provide the Visual Basic compiler with all the information about the classes, methods, properties, and so forth implemented in the DLLs. These same DLLs are later linked with the running program to implement these classes. Some programs later in this book have an Imports statement:

Imports System.Drawing.Drawing2D

This is a namespace consisting of classes and other items also located in the dynamic-link library System.Drawing.dll.


Previous   |  Table of Contents   |   Next



Last Updated: August 7, 2002
Top of Page