
- •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

700 Chapter 15 PRINTING WITH VB.NET
Printing simple reports (tabular data) is another common printing task. You can draw an outline of the printout on paper and then implement it with VB code. The data will most likely come from a database, so you don’t really need to create an application with an elaborate interface. Printing graphics is straightforward—but not typical in business applications. All the graphics commands you use to generate a graphic on the screen can be applied to the printer as well. The most complicated case is the printing of formatted text.
The examples of this section will address many of your day-to-day needs, and I’m including examples that will serve as your starting point for some of the most typical printing needs, from printing tabular data to bitmaps.
VB6 VB.NET
VB6 included some mechanisms to simplify the generation of simple printouts. These mechanisms are no longer available. On the plus side, VB.NET provides a unified approach for generating all types of printouts. Generating a preview, for example, is no longer a separate process. Whether you print on a printer or in the preview pane, the process is identical.
The Printing Objects
We’ll start our exploration of Visual Basic’s printing capabilities with an overview of the printing process, which is the same no matter what you print. Printing with VB.NET is equivalent to drawing on a Form or PictureBox object. VB.NET introduced several controls for generating output for the printer, and here’s a quick overview of these objects (you’ll find more information on these objects and examples in the following sections). You don’t need to use all these objects in your project. Only the PrintDocument object is required, and you will have to master the members of this control.
PrintDocument
This object represents your printer, and you must add a PrintDocument control to any project that generates printer output. In effect, everything you draw on the PrintDocument object is sent to the printer. The PrintDocument object represents the printing surface, and it exposes a Graphics object. You can program against the Graphics object using all the methods discussed in Chapter 14. If you can create drawings on a form, you can just as easily print them on your printer. To print text, for example, you must call the DrawString method. To print headers and footers, you supply the text to be printed, the coordinates on the page where the string will be printed, and the font in which the string will be rendered. You can also print frames around the text with the DrawLine or DrawRectangle method. In general, you can use all the methods of the Graphics object to prepare the printout.
To send something to the printer, you must first add an instance of the PrintDocument control to the project. This control is invisible at runtime, and its icon will appear on the Components tray at design time. When you’re ready to print, call the PrintDocument object’s Print method. This method isn’t going to produce any output, but it will raise the PrintPage event. This is where you must insert the code that generates output for the printer. The PrintPage event passes the e argument, which exposes the Graphics property of the current Printer object, among other members.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

THE PRINTING OBJECTS 701
This is same object we used in the previous chapter to generate all kinds of graphics. The printer has its own Graphics object, which represents the page you print on. All the methods that generate graphics can be applied to the printer’s Graphics object to print graphics on the page. The following statement initiates the printing:
PrintDocument1.Print
This statement is usually placed in a button’s or a menu item’s Click event handler. To experiment with simple printouts, create a new project, place a button on the form, and add an instance of the PrintDocument object to the project. Enter the previous statement in the button’s Click event handler.
After the execution of this statement, the PrintDocument1_PrintPage event handler takes over. This event is fired for each page, so you insert the code to print the first page in this event’s handler. If you need to print additional pages, you set the e.HasMorePages property to True just before you exit the event handler. This will fire another PrintPage event. The same process will repeat until you’ve printed everything. When you’ve finished, you set the e.HasMorePages property to False, and no more PrintPage events will be fired. Figure 15.1 outlines the printing process.
Figure 15.1 |
|
|
|
|
|
|
Event Handlers |
|
|
|||
All printing takes |
|
|
|
|
|
|
|
|
||||
place in the Print- |
|
PrintDocument.Print |
|
|
|
|
BeginPrint |
|
|
|
||
Page event handler of |
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
Insert initialization code here |
|
|
|
|||
|
|
|
|
|
||||||||
the PrintDocument |
|
|
|
|
|
|
|
|
|
|
|
|
object. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PrintPage |
|
|
|
||
|
|
|
|
|
|
|
Insert code to print next page |
|
|
|
||
|
|
|
|
|
|
|
|
HasMorePages = True |
||||
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
HasMorePages = False |
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EndPrint |
|
|
|
||
|
|
|
|
|
|
|
Insert clean-up code here |
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
||
|
Initialize the printing process… |
|
|
|
and program these events to handle the printing. |
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
The code in Listing 15.1 shows the structure of a typical PrintPage event handler. The PrintPage event handler prints three pages with the same text and a different page number on each page.
Listing 15.1: A Simple PrintPage Event Handler
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _ Handles PrintDocument1.PrintPage
Static pageNum As Integer
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

702 Chapter 15 PRINTING WITH VB.NET
Dim prFont As New Font(“Verdana”, 24, GraphicsUnit.Point) e.Graphics.DrawString(“PAGE “ & pageNum + 1, prFont, _
Brushes.Black, 700, 1050) e.Graphics.DrawRectangle(Pens.Blue, 0, 0, 300, 100) e.Graphics.DrawString(“Printing with VB.NET”, prFont, _
Brushes.Black, 10, 10)
‘Add more printing statements here
‘Following is the logic that determines whether we’re done printing
pageNum = pageNum + 1 If pageNum <= 3 Then
e.HasMorePages = True Else
e.HasMorePages = False End If
End Sub
Notice that the page number is printed at the bottom of the page, but the corresponding statement is the first one in the subroutine. I’m assuming you’re using an letter-size page, so I’ve hardcoded the coordinates of the various elements in the code. Later in this chapter, you’ll learn how to take into consideration not only the dimensions of the physical page but its orientation, too.
You can draw anywhere you like on the page. The PrintDocument object accumulates all the graphics commands and sends them to the printer when the PrintPage event handler terminates. So, the order in which you place the various elements on the page doesn’t matter. You can also draw overlapping shapes, like placing text over a bitmap or drawing arrows over a chart.
The code of Listing 15.1 prints three pages, with the same text and different page numbers. While there are more pages to be printed, the program sets the e.HasMorePages property to True. After printing the last page, it sets the same argument to False to prevent further invocations of the PrintPage event. Note that the pageNum variable was declared as static, so that it will retain its value between calls.
The entire printout is generated by the same subroutine, one page at a time. Because pages are not totally independent of one another, we need to keep some information in variables that are not initialized every time the PrintPage event handler is executed. The page number, for example, must be stored in a variable that will maintain its value between successive invocations of the PrintPage event handler, and it must be increased every time a new page is printed. If you’re printing a text file, you must keep track of the current text line, so that each page will pick up where the previous one ended and not from the beginning of the document. You can use static variables or declare variables on the form’s level, whatever suits you best. This is a recurring theme in programming the PrintPage event, and you’ll see many more examples of this technique in the following sections.
PrintDialog
The PrintDialog control displays the standard Print dialog box, shown in Figure 15.2, which allows users to select a printer and set its properties. If you don’t display this dialog box, the output will be sent automatically to the default printer and will use the default settings of the printer. The Print
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

THE PRINTING OBJECTS 703
dialog box was discussed in Chapter 7, and you already know how to retrieve the selected printer, as well as the settings specified by the user, in the dialog box. In this chapter, you’ll see how to use these settings in the code that generates output for the printer.
Figure 15.2
The Print dialog box
Among other settings, the Print dialog box allows you to specify the range of pages to be printed. Before allowing users to select a range of pages, be sure that you have a way to skip any number of pages. If the user specifies pages 10 through 19, your code must calculate the section of the document that would normally be printed on the first nine pages, skip it, and start printing after that. If the printout is a report with a fixed number of rows per page, skipping pages is trivial. If the printout contains formatted text, you must repeat all the calculations to generate the first nine pages and ignore them (skip the statements that actually print the graphics). Starting a printout at a page other than the first one can be a challenge.
When you select a printer from this dialog box, it automatically becomes the active printer and any printout generated after the selection of the printer will be sent to this printer; you don’t have to insert any code to switch printers.
The actual printer to which you will send the output of your application is almost transparent to the printing code. The same commands will generate the same output on any printer. If you’re using a color printer, you may insert additional code to generate colored output. If you’re using a plotter, you’ll also want to print all the components of the same color together, to minimize the time spent by the plotter in changing pens. For the most common printers—that is, ink-jet and PostScript printers—you don’t have to modify a single statement. The same code will work with all printers.
It is also possible to set the printer from within your code with a statement like the following:
PrintDocument1.PrinterSettings.PrinterName = printer
where printer is the name of one of the installed printers. For more information on selecting a printer form within your code, see the section “Printer and Page Properties,” later in this chapter. There are situations where you want to set a printer from within your code and not give users a chance to change it. An application that prints invoices and reports, for example, must use a different printer for each type of printout.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |