Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
120
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

818 Chapter 18 RECURSIVE PROGRAMMING

Recursion by Mistake

Recursion isn’t as complicated as you may think. Here’s an example of a recursive situation you may have experienced without knowing it. Figure 18.4 shows a simple application that fills the background of a PictureBox with a solid color. Instead of setting the control’s BackColor property, though, it draws vertical lines from one end of the control to the other. Every time the Color Box button is clicked, the PictureBox control is filled slowly with vertical lines. The color of the lines is chosen randomly. The application runs too fast for you to notice the progress of the painting, so I’ve inserted a statement to invalidate the control after drawing each line. I’ve also included a loop that redraws each line 20 times, to make sure the process is slow and so you can interrupt it (you’ll understand shortly why this is necessary). If you’re running this application on a computer that’s much faster than mine, you must increase this value to slow down the application.

Figure 18.4

Click the Color Box button before the program has a chance to fill the control to watch a recursive behavior.

VB.NET at Work: The Recurse Project

You’ll find the Recurse application in this chapter’s folder on the CD. Load it and run it. Click the Color Box button, and the program will start filling the PictureBox with a random color from left to right. Because of the way the control is filled, the progress of the drawing is slow, even on a fast Pentium. The code behind the Color Box Command button is shown in Listing 18.2.

Listing 18.2: The Color Box Button

Private Sub Button1_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button1.Click Static bmp As New Bitmap(PictureBox1.ClientSize.Width, _

PictureBox1.ClientSize.Height)

Dim clr As Color

Dim rnd As New System.Random() Dim G As Graphics PictureBox1.Image = bmp

G = Graphics.FromImage(bmp)

clr = Color.FromARGB(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255))

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

BASIC CONCEPTS 819

Dim X As Integer

For X = 0 To PictureBox1.Width - 1

G.DrawLine(New Pen(clr), X, 0, X, PictureBox1.Height)

PictureBox1.Invalidate()

Application.DoEvents()

Next

End Sub

Suppose the program starts filling the picture box with red lines. Before the program has a chance to complete its operation, click the Color Box button again. The button’s Click event handler is interrupted, and the program starts filling the control with a new color, perhaps fuchsia. Interrupt the process again. This time, yellow kicks in and starts filling the control from left to right. Let this operation complete.

As soon as the picture box is filled with yellow, the interrupted process will resume. The program completes the drawing of the fuchsia lines, but it doesn’t start drawing from the left edge of the control. It picks up from where it was interrupted. When the fuchsia color reaches the right edge of the control, red kicks in! Can you see what’s going on here? Each time you click the Color Box button, the Click event handler of the button is interrupted, and a new copy of the same subroutine starts executing. The interrupted (or suspended) instance of the subroutine doesn’t die. It waits for a chance to complete, which it gets when the newer instance of the subroutine completes its task.

This recursion is made possible by the Application.DoEvents() statement placed in the loop’s body. Without it, you wouldn’t be able to interrupt the subroutine and invoke another instance of it. Normally, you wouldn’t call the DoEvents() method to avoid the very behavior you witnessed in this example. Most of the procedures you’ve written so far don’t use the DoEvents() statement; these procedures won’t allow another procedure to start executing before they have finished.

Avoiding Recursion

If you comment out the Application.DoEvents() statement in the listing, you won’t be able to interrupt the process of coloring the control. The application, however, will become less responsive. While the loop is executing, you won’t be able to even move the window on the desktop. Can you make the application more responsive by including the call to the DoEvents method, yet avoid the side effect of the recursive behavior? You can set up a static variable, which will be set to True while the loop is executing. You examine this variable’s value before entering the loop. If it’s True, you must exit immediately. If it’s False, set it to True and continue. When the loop terminates, reset it to False:

Static Executing As Boolean

‘ variable initialized to False

If Executing Then Exit Sub

 

Executing = True

 

{ procedure’s statements }

 

Executing = False

 

This is a simple technique to prevent the multiple executions of the same procedure. Obviously, this technique applies to regular procedures and shouldn’t be used with recursive procedures.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com