- •Using Your Sybex Electronic Book
- •Acknowledgments
- •Contents at a Glance
- •Introduction
- •Who Should Read This Book?
- •How About the Advanced Topics?
- •The Structure of the Book
- •How to Reach the Author
- •The Integrated Development Environment
- •The Start Page
- •Project Types
- •Your First VB Application
- •Making the Application More Robust
- •Making the Application More User-Friendly
- •The IDE Components
- •The IDE Menu
- •The Toolbox Window
- •The Solution Explorer
- •The Properties Window
- •The Output Window
- •The Command Window
- •The Task List Window
- •Environment Options
- •A Few Common Properties
- •A Few Common Events
- •A Few Common Methods
- •Building a Console Application
- •Summary
- •Building a Loan Calculator
- •How the Loan Application Works
- •Designing the User Interface
- •Programming the Loan Application
- •Validating the Data
- •Building a Math Calculator
- •Designing the User Interface
- •Programming the MathCalculator App
- •Adding More Features
- •Exception Handling
- •Taking the LoanCalculator to the Web
- •Working with Multiple Forms
- •Working with Multiple Projects
- •Executable Files
- •Distributing an Application
- •VB.NET at Work: Creating a Windows Installer
- •Finishing the Windows Installer
- •Running the Windows Installer
- •Verifying the Installation
- •Summary
- •Variables
- •Declaring Variables
- •Types of Variables
- •Converting Variable Types
- •User-Defined Data Types
- •Examining Variable Types
- •Why Declare Variables?
- •A Variable’s Scope
- •The Lifetime of a Variable
- •Constants
- •Arrays
- •Declaring Arrays
- •Initializing Arrays
- •Array Limits
- •Multidimensional Arrays
- •Dynamic Arrays
- •Arrays of Arrays
- •Variables as Objects
- •So, What’s an Object?
- •Formatting Numbers
- •Formatting Dates
- •Flow-Control Statements
- •Test Structures
- •Loop Structures
- •Nested Control Structures
- •The Exit Statement
- •Summary
- •Modular Coding
- •Subroutines
- •Functions
- •Arguments
- •Argument-Passing Mechanisms
- •Event-Handler Arguments
- •Passing an Unknown Number of Arguments
- •Named Arguments
- •More Types of Function Return Values
- •Overloading Functions
- •Summary
- •The Appearance of Forms
- •Properties of the Form Control
- •Placing Controls on Forms
- •Setting the TabOrder
- •VB.NET at Work: The Contacts Project
- •Anchoring and Docking
- •Loading and Showing Forms
- •The Startup Form
- •Controlling One Form from within Another
- •Forms vs. Dialog Boxes
- •VB.NET at Work: The MultipleForms Project
- •Designing Menus
- •The Menu Editor
- •Manipulating Menus at Runtime
- •Building Dynamic Forms at Runtime
- •The Form.Controls Collection
- •VB.NET at Work: The DynamicForm Project
- •Creating Event Handlers at Runtime
- •Summary
- •The TextBox Control
- •Basic Properties
- •Text-Manipulation Properties
- •Text-Selection Properties
- •Text-Selection Methods
- •Undoing Edits
- •VB.NET at Work: The TextPad Project
- •Capturing Keystrokes
- •The ListBox, CheckedListBox, and ComboBox Controls
- •Basic Properties
- •The Items Collection
- •VB.NET at Work: The ListDemo Project
- •Searching
- •The ComboBox Control
- •The ScrollBar and TrackBar Controls
- •The ScrollBar Control
- •The TrackBar Control
- •Summary
- •The Common Dialog Controls
- •Using the Common Dialog Controls
- •The Color Dialog Box
- •The Font Dialog Box
- •The Open and Save As Dialog Boxes
- •The Print Dialog Box
- •The RichTextBox Control
- •The RTF Language
- •Methods
- •Advanced Editing Features
- •Cutting and Pasting
- •Searching in a RichTextBox Control
- •Formatting URLs
- •VB.NET at Work: The RTFPad Project
- •Summary
- •What Is a Class?
- •Building the Minimal Class
- •Adding Code to the Minimal Class
- •Property Procedures
- •Customizing Default Members
- •Custom Enumerations
- •Using the SimpleClass in Other Projects
- •Firing Events
- •Shared Properties
- •Parsing a Filename String
- •Reusing the StringTools Class
- •Encapsulation and Abstraction
- •Inheritance
- •Inheriting Existing Classes
- •Polymorphism
- •The Shape Class
- •Object Constructors and Destructors
- •Instance and Shared Methods
- •Who Can Inherit What?
- •Parent Class Keywords
- •Derived Class Keyword
- •Parent Class Member Keywords
- •Derived Class Member Keyword
- •MyBase and MyClass
- •Summary
- •On Designing Windows Controls
- •Enhancing Existing Controls
- •Building the FocusedTextBox Control
- •Building Compound Controls
- •VB.NET at Work: The ColorEdit Control
- •VB.NET at Work: The Label3D Control
- •Raising Events
- •Using the Custom Control in Other Projects
- •VB.NET at Work: The Alarm Control
- •Designing Irregularly Shaped Controls
- •Designing Owner-Drawn Menus
- •Designing Owner-Drawn ListBox Controls
- •Using ActiveX Controls
- •Summary
- •Programming Word
- •Objects That Represent Text
- •The Documents Collection and the Document Object
- •Spell-Checking Documents
- •Programming Excel
- •The Worksheets Collection and the Worksheet Object
- •The Range Object
- •Using Excel as a Math Parser
- •Programming Outlook
- •Retrieving Information
- •Recursive Scanning of the Contacts Folder
- •Summary
- •Advanced Array Topics
- •Sorting Arrays
- •Searching Arrays
- •Other Array Operations
- •Array Limitations
- •The ArrayList Collection
- •Creating an ArrayList
- •Adding and Removing Items
- •The HashTable Collection
- •VB.NET at Work: The WordFrequencies Project
- •The SortedList Class
- •The IEnumerator and IComparer Interfaces
- •Enumerating Collections
- •Custom Sorting
- •Custom Sorting of a SortedList
- •The Serialization Class
- •Serializing Individual Objects
- •Serializing a Collection
- •Deserializing Objects
- •Summary
- •Handling Strings and Characters
- •The Char Class
- •The String Class
- •The StringBuilder Class
- •VB.NET at Work: The StringReversal Project
- •VB.NET at Work: The CountWords Project
- •Handling Dates
- •The DateTime Class
- •The TimeSpan Class
- •VB.NET at Work: Timing Operations
- •Summary
- •Accessing Folders and Files
- •The Directory Class
- •The File Class
- •The DirectoryInfo Class
- •The FileInfo Class
- •The Path Class
- •VB.NET at Work: The CustomExplorer Project
- •Accessing Files
- •The FileStream Object
- •The StreamWriter Object
- •The StreamReader Object
- •Sending Data to a File
- •The BinaryWriter Object
- •The BinaryReader Object
- •VB.NET at Work: The RecordSave Project
- •The FileSystemWatcher Component
- •Properties
- •Events
- •VB.NET at Work: The FileSystemWatcher Project
- •Summary
- •Displaying Images
- •The Image Object
- •Exchanging Images through the Clipboard
- •Drawing with GDI+
- •The Basic Drawing Objects
- •Drawing Shapes
- •Drawing Methods
- •Gradients
- •Coordinate Transformations
- •Specifying Transformations
- •VB.NET at Work: Plotting Functions
- •Bitmaps
- •Specifying Colors
- •Defining Colors
- •Processing Bitmaps
- •Summary
- •The Printing Objects
- •PrintDocument
- •PrintDialog
- •PageSetupDialog
- •PrintPreviewDialog
- •PrintPreviewControl
- •Printer and Page Properties
- •Page Geometry
- •Printing Examples
- •Printing Tabular Data
- •Printing Plain Text
- •Printing Bitmaps
- •Using the PrintPreviewControl
- •Summary
- •Examining the Advanced Controls
- •How Tree Structures Work
- •The ImageList Control
- •The TreeView Control
- •Adding New Items at Design Time
- •Adding New Items at Runtime
- •Assigning Images to Nodes
- •Scanning the TreeView Control
- •The ListView Control
- •The Columns Collection
- •The ListItem Object
- •The Items Collection
- •The SubItems Collection
- •Summary
- •Types of Errors
- •Design-Time Errors
- •Runtime Errors
- •Logic Errors
- •Exceptions and Structured Exception Handling
- •Studying an Exception
- •Getting a Handle on this Exception
- •Finally (!)
- •Customizing Exception Handling
- •Throwing Your Own Exceptions
- •Debugging
- •Breakpoints
- •Stepping Through
- •The Local and Watch Windows
- •Summary
- •Basic Concepts
- •Recursion in Real Life
- •A Simple Example
- •Recursion by Mistake
- •Scanning Folders Recursively
- •Describing a Recursive Procedure
- •Translating the Description to Code
- •The Stack Mechanism
- •Stack Defined
- •Recursive Programming and the Stack
- •Passing Arguments through the Stack
- •Special Issues in Recursive Programming
- •Knowing When to Use Recursive Programming
- •Summary
- •MDI Applications: The Basics
- •Building an MDI Application
- •Built-In Capabilities of MDI Applications
- •Accessing Child Forms
- •Ending an MDI Application
- •A Scrollable PictureBox
- •Summary
- •What Is a Database?
- •Relational Databases
- •Exploring the Northwind Database
- •Exploring the Pubs Database
- •Understanding Relations
- •The Server Explorer
- •Working with Tables
- •Relationships, Indices, and Constraints
- •Structured Query Language
- •Executing SQL Statements
- •Selection Queries
- •Calculated Fields
- •SQL Joins
- •Action Queries
- •The Query Builder
- •The Query Builder Interface
- •SQL at Work: Calculating Sums
- •SQL at Work: Counting Rows
- •Limiting the Selection
- •Parameterized Queries
- •Calculated Columns
- •Specifying Left, Right, and Inner Joins
- •Stored Procedures
- •Summary
- •How About XML?
- •Creating a DataSet
- •The DataGrid Control
- •Data Binding
- •VB.NET at Work: The ViewEditCustomers Project
- •Binding Complex Controls
- •Programming the DataAdapter Object
- •The Command Objects
- •The Command and DataReader Objects
- •VB.NET at Work: The DataReader Project
- •VB.NET at Work: The StoredProcedure Project
- •Summary
- •The Structure of a DataSet
- •Navigating the Tables of a DataSet
- •Updating DataSets
- •The DataForm Wizard
- •Handling Identity Fields
- •Transactions
- •Performing Update Operations
- •Updating Tables Manually
- •Building and Using Custom DataSets
- •Summary
- •An HTML Primer
- •HTML Code Elements
- •Server-Client Interaction
- •The Structure of HTML Documents
- •URLs and Hyperlinks
- •The Basic HTML Tags
- •Inserting Graphics
- •Tables
- •Forms and Controls
- •Processing Requests on the Server
- •Building a Web Application
- •Interacting with a Web Application
- •Maintaining State
- •The Web Controls
- •The ASP.NET Objects
- •The Page Object
- •The Response Object
- •The Request Object
- •The Server Object
- •Using Cookies
- •Handling Multiple Forms in Web Applications
- •Summary
- •The Data-Bound Web Controls
- •Simple Data Binding
- •Binding to DataSets
- •Is It a Grid, or a Table?
- •Getting Orders on the Web
- •The Forms of the ProductSearch Application
- •Paging Large DataSets
- •Customizing the Appearance of the DataGrid Control
- •Programming the Select Button
- •Summary
- •How to Serve the Web
- •Building a Web Service
- •Consuming the Web Service
- •Maintaining State in Web Services
- •A Data-Driven Web Service
- •Consuming the Products Web Service in VB
- •Summary
SPECIAL ISSUES IN RECURSIVE PROGRAMMING 831
A Real-Life Example
Imagine that you are so disciplined and organized that you can place every document you use in your office on top of a document stack. Every time you’re interrupted by a visitor or a phone call, you leave the document you were working with on top of this paper stack and remove another document from your filing cabinet to work on. When you’ve finished, you take the document in front of you and place it back in the filing cabinet (or if you’re interrupted again, you place this document on the stack and retrieve another one from the filing cabinet).
What you now have in front of you is the document you were working on when you were interrupted. When you’ve finished with this document, you put it back where it belongs and another document surfaces on the stack—the document you interrupted working on to work with another document. After you work with this document, revise it, and put it away, you have another document before you from an even earlier interruption. If you can maintain this type of organization, you’ll never need to waste time looking for documents (and your productivity will be at an all-time high!). Everything will be in its filing space, and most of the time, the document you need will be right in front of you. Thankfully, we’re not as simplistic as our computers, nor do we need to be so rigid. But you’ll probably agree that this type of memory organization makes perfect sense for keeping track of interrupted tasks on your computer.
Special Issues in Recursive Programming
Recursion is not a technique that most programmers regularly use. Only a few situations call for recursive programming, and unfortunately, these programs can’t be implemented otherwise. As the various object models become more and more complicated, you’ll have to implement an increasing number of recursive procedures. The following sections discuss the dangers of recursion and give you a few hints to help you recognize a procedure that calls for recursive programming.
It’s Easy to Write a Never-Ending Program
If you forget to specify an exit condition with a few statements that stop the procedure from calling itself, you’ll end up with a never-ending program, or an endless loop. If this happens, your computer will run out of memory for storing the intermediate results, and the program will end with the “Out of stack space” error message. The memory available for storing intermediate results between procedure calls is limited and it’s easy to exhaust.
The stack isn’t used only for recursive procedures. Each time a function is called, the status of the one that’s interrupted, along with the arguments of the function being called, are stored on the stack. It’s practically impossible to run out of stack space with regular procedures; to do so, you’d have to call an extremely large number of procedures, one from within the other. You can run out of stack space with recursive procedures, though, because you don’t have to write several thousand routines— only one that calls itself and doesn’t provide an exit mechanism.
I’ve tried to produce a stack overflow by calculating the factorial of a very large number. While this was easy with previous versions of VB, this time I’ve exhausted the accuracy of the Long data type before generating a stack overflow. I even changed the Factorial() function’s type to Double to fill the stack, but guess what happened: the string “Infinity” appeared on the form! The ScanFolder() subroutine will never generate a stack overflow, because I can’t imagine a file system with nested folders to a depth of several hundreds.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
832 Chapter 18 RECURSIVE PROGRAMMING
I had to write a dummy subroutine that calls itself to cause the stack to overflow. After more than 40,000 recursive calls, the stack was exhausted. To be on the safe side, you can catch the StackOverflowException in your code.
Knowing When to Use Recursive Programming
In addition to knowing how to implement recursive programming, you need to know when to use it. The recursive nature of many problems isn’t obvious, so it may take a while to get the hang of it. (We humans aren’t trained to think recursively, but once you’ve established the recursive nature of a problem, the recursive algorithm will follow quite naturally.) An algorithm that, in the middle of carrying out a task, has to start and complete an identical task is a prime candidate for recursive implementation. Consider a procedure for scanning the contents of a folder. First, it counts the files. If the folder has subfolders, the same process must be repeated for each subfolder.
If you find yourself nesting loops in many levels or if you’re trying to set up conditions to exit these loops prematurely, your code would probably benefit from a recursive implementation. Recursion bears some resemblance to iteration, and in some situations, you can implement a recursive algorithm with a loop. The factorial algorithm, for instance, can be easily implemented with a For…Next loop. But there are situations in which iterations won’t help.
Try It!
If you’re interested in recursion and would like to experiment a little, here’s a problem that can be solved both recursively and nonrecursively: Write a program that accepts a phone number and produces all possible seven-letter combinations that match the phone number (vanity numbers, as they are called). This is not a trivial task, no matter how you look at it. There are 3 to the power of 7, or 2,187, possible combinations, because each number can be mapped to one of three letters and phone numbers have seven digits (excluding the area code).
I’ve mentioned already that recursive routines are quite common when programming with classes of .NET Framework. You have already seen a few recursive routines in earlier chapters, and I would like to go through a couple of typical examples presented in earlier chapters. In Chapter 5, you saw a recursive procedure for scanning the items of a menu, and in Chapter 16, you saw a recursive procedure for scanning the nodes of a TreeView control. Now that you have a better understanding of how recursion works, you may wish to take a closer look at these applications. In the following sections, I will focus on the recursive nature of these routines and not on the object models used in each example.
Printing a Menu’s Commands
In Chapter 5, you saw a subroutine that iterates through the items of a menu. If an item leads to a submenu, the submenu’s items are also scanned, and this process is repeated to any depth. Of course, no menu item should be nested in more than two or three levels, but this procedure will work with any menu structure. The following code iterates through the items of a MainMenu object and prints all the commands in the Output window. MapMenu is the name of a button on a form with a menu,
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
SPECIAL ISSUES IN RECURSIVE PROGRAMMING 833
and it prints the names of the commands at the top level. It scans all the items of the menu’s MenuItems collection and prints their captions. After printing each command’s caption, it calls the PrintSubMenu() subroutine, passing the current MenuItem as argument. The PrintSubMenu() subroutine iterates through the items of the collection passed as argument and prints their captions. The MapMenu command’s code is shown here:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim itm As MenuItem
For Each itm In Me.Menu.MenuItems
TextBox1.AppendText(itm.Text & vbCrLf)
PrintSubMenu(itm)
Next
End Sub
The PrintSubMenu() subroutine, shown in the following code, goes through the MenuItems collection of the MenuItem object passed as argument and prints the captions of its items. If the current item leads to a submenu (in other words, if it has its own MenuItems collection), it calls the PrintSubMenu() subroutine recursively. The PrintSubMenu() subroutine is called with a different argument every time, and this argument is the current menu item—the item whose submenu we want to scan.
Sub PrintSubMenu(ByVal MItem As MenuItem) Static indentLevel As Integer indentLevel += 5
Dim itm As New MenuItem()
For Each itm In MItem.MenuItems TextBox1.AppendText(Space(indentLevel) & itm.Text & vbCrLf) If itm.MenuItems.Count > 0 Then PrintSubMenu(itm)
Next indentLevel -= 5
End Sub
When the PrintSubMenu() subroutine starts executing, it increases the variable indentLevel by 5. This variable is the number of spaces printed in front of each item’s caption. We increase the indentation level by five spaces every time we run into a new submenu, and we decrease it every time we move to the previous menu level. When the PrintSubMenu() subroutine finishes processing a submenu, the indentation is decreased by five spaces, so that items on the same level have the same indentation.
Printing the Nodes of a TreeView Control
Scanning the nodes of a TreeView control is another typical example of a recursive procedure, because each node may have a collection of nodes under it, and this can go on to any depth. For the purposes of our example, we’ll assume that the TreeView control has a single root node. This isn’t an unreasonable assumption, because most tree structures have a single root and you should try to implement trees with a single root node to simplify your code. If you have a tree with multiple root nodes, you must write a loop that iterates through the root nodes, and for each node you must call the ScanNode() recursive procedure.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |