- •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
PRINTING EXAMPLES 733
rectangle as possible, even if the last line fits only partially in the rectangle. To force the MeasureString and DrawString methods to work with an integer number of lines, create a FormatString object passing the constant StringFormatFlags.LineLimit as argument:
Dim fmt As New StringFormat(StringFormatFlags.LineLimit)
If you pass the fmt object as argument to both the MeasureString and DrawString methods, they will ignore partial lines and the rest of the printing code works as expected.
If the user changes the orientation of the page, the code switches the page’s width and height. This is all it takes to print text in landscape orientation. The page’s margins are also accounted for.
Before ending this section, I should explain why I haven’t started with this version of the application (which is also simpler that the PrintText project of the previous section). The PrintText2 application prints one page at a time. You have no control over the individual lines or words. The granularity of the PrintText2 application is an entire page. If the text contains formatting information (simple tags to turn on and off the attributes like bold and italics), you won’t be able to process them. Assume that the text contains HTML-like tags (like the <B> and <I> tags) to determine the appearance of the text, or custom tags to specify the formatting of section headers. When you treat a block of text as a single entity, you won’t be able to process individual words.
The same is true for simpler types of processing. Let’s say you want to format a program listing by inserting a continuation symbol at the end of every code line that has to be broken into two or more text lines. Since we rely on the DrawString method to break long code lines into multiple text lines for us, we can’t insert the appropriate symbols, or indent the continued lines, as is customary in program listings. It’s also common to number the lines of program listings. Even this simple operation can’t be incorporated into the PrintText2 application’s project. So a text-printing application that prepares the page one word at a time may be slow, but it’s flexible, and you’re more likely to write code based on the PrintText sample application. The technique demonstrated by the PrintText2 application is a convenient method of printing simple text files, similar to printing them with Notepad.
Printing Bitmaps
If you have a color printer, you probably want to print images, too. Printing bitmaps is quite simple. As you have probably guessed, you call the DrawImage method to send the bitmap to the printer. As a reminder, the simplest form of the DrawImage method of the Graphics object accepts two arguments, which are the bitmap to be drawn (an Image object) and a rectangle in which the image will be drawn:
Graphics.DrawImage(image, rectangle)
The method will stretch the bitmap specified by the image argument to fill the rectangle specified by the second argument. Because of this, it is imperative that you calculate carefully the dimensions of the rectangle, so that they will retain their original aspect ratio. If not, the image will be distorted in the process. Most applications will let the user specify a zoom factor, which is then applied to both dimensions. If the image fits on the page, you can make the rectangle equal to the dimensions of the image and not worry about distortions.
Since the reduced image will, most likely, be smaller than the dimensions of the paper on which it will be printed, you must also center the image on the paper. To do so, you can subtract the image’s width from the paper’s width and split the difference on the two sides of the image (you will do the same for the vertical margins).
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
734 Chapter 15 PRINTING WITH VB.NET
If you specify a rectangle the same size as the image, the image will be printed in its actual size. A common image resolution is 72 dots per inch. If the bitmap is 1,024 pixels wide, it will take approximately 14 inches across the page—this means that part of the image won’t be printed.
Figure 15.10
The PrintBitmap application resizes bitmaps to fit the width of the page and prints them.
Before you send a bitmap to the printer, you must first make sure the bitmap will fit on the page. If the bitmap is too large for a letter-size page, you must reduce its size. Fortunately, the Framework can handle this for you. All you have to do is specify the size of the rectangle on the paper, in which the image will be printed. The following statements, which must appear in the PrintDocument event, print the image centered on the page. If the image doesn’t fit on the page, its top-left corner is printed at the origin, and only the rightmost and bottommost parts of the image will be missing. Notice also that the image isn’t printed in actual size; instead, it’s printed at the current magnification. Listing 15.13 provides the code of the PrintPage event handler.
Listing 15.13: Scaling and Printing a Bitmap
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
Handles PrintDocument1.PrintPage
Dim R As Rectangle
Dim PictWidth, PictHeight, PictLeft, PictTop As Integer
PictWidth = PictureBox1.Width
PictHeight = PictureBox1.Height
With PrintDocument1.DefaultPageSettings.PaperSize
If PictWidth < .Width Then
PictLeft = (.Width - PWidth) / 2
Else
PictLeft = 0
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
PRINTING EXAMPLES 735
End If
If PictHeight < .Height Then PictTop = (.Height - PHeight) / 2
Else
PictTop = 0 End If
End With
R = New Rectangle(PictLeft, PictTop, PictWidth, PictHeight) e.Graphics.DrawImage(PictureBox1.Image, R)
End Sub
The PictWidth and PictHeight variables hold the dimensions of the scaled image, while PictLeft and PictTop are the coordinates of the image’s top-left corner on the page. To initiate the printing process, you must call the PrintDocument object’s Print method, or you can display the PrintPreview dialog box, which is what the following code does:
Private Sub bttnPrint_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
PrintPreviewDialog1.Document = PrintDocument1
PrintPreviewDialog1.ShowDialog()
End Sub
The user can resize and rotate the image before printing it. These rotation commands can be found in the main form’s Process menu, while the Zoom menu has four options: Auto, Normal, Zoom In, and Zoom Out (Figure 15.11). The last two commands zoom in and out by 25 percent at a time. These commands change the size of the PictureBox control that holds the image, and the PrintPage event handler uses the dimensions of this control to determine the dimensions of the printed image. The Normal command resets the image to its actual size, and the Auto command resizes the image proportionally so that its height is 400 pixels.
Figure 15.11
The PrintBitmap application’s main form
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
736 Chapter 15 PRINTING WITH VB.NET
Using the PrintPreviewControl
The PrintPreviewControl is the core of the PrintPreviewDialog control packaged as a Windows control. It consists of the preview pane, where the printed document can be previewed. Other than that, it has a vertical and horizontal scroll bar but no controls to zoom or to move from
page to page. You can use this control to create a custom print-preview form for specialized applications, but you must design an interface that will allow users to navigate through the document being viewed. You should use the PrintPreviewDialog control instead, but if you want to use a different interface or restrict the preview pane on a form, you’ll find all the information you need to program the PrintPreviewControl in this section.
Just like its cousin, the PrintPreviewDialog, the PrintPreviewControl requires the presence of
a PrintDocument control. This control will provide the document to be viewed and will expose the PrintPage event, where all the action takes place. Once you’ve added a PrintPreviewControl and a PrintDocument control to the project, you can assign the instance of the PrintDocument control to the Document property of the PrintPreviewControl with a statement like the following, and you’re ready to preview:
PrintPreviewControl1.Document = PrintDocument1
Unlike the PrintPreviewDialog control, the PrintPreviewControl is visible at runtime. Not only that, but you need quite a bit of space on your form for this control to work. Figure 15.12 shows a form with a TextBox control on the left and a PrintPreviewControl on the right. The interface for previewing the document is quite trivial, but it demonstrates the basic properties of the control.
We’ll get to the interface shortly.
First, size the control on the form. You should probably dock it on the edges of the form, so that users can control the preview pane’s size. Then place the Preview button on the form and enter the following code in its Click event handler:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
PrintPreviewControl1.Columns = 2
PrintPreviewControl1.Document = PrintDocument1
End Sub
The Columns property determines how many pages appear next to each other on the control. There’s also a Rows property, which determines how many rows of pages are on the control. To display four pages at a time on the control, set both properties to 2.
After setting the control’s Document property, you can insert the code to generate the printout in the PrintDocument control’s PrintPage event handler. The output will be sent to the Preview control, not to the printer, or even to the PrintPreview dialog box. In this example we’ll print eight pages, so that you can experiment with the various settings of the control. We’ll print the text on the TextBox control on eight pages (all pages will display the same text). Each page will be differentiated by the page number, which will appear in bold at the top of the page, as shown in Figure 15.12. Listing 15.14 shows the code in the PrintPage event handler.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
PRINTING EXAMPLES 737
Listing 15.14: Printing a Simple Document to the PrintPreview Control
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _ Handles PrintDocument1.PrintPage
Static iPage As Integer
e.Graphics.DrawString(“PAGE # “ & (iPage+ 1).ToString, _
New Font(“Comic sans MS”, 24), Brushes.Black, 10, 10) e.Graphics.DrawString(RichTextBox1.Text, RichTextBox1.Font, _
Brushes.Black, 50, 50)
iPage = iPage + 1 If iPage = 8 Then
e.HasMorePages = False Else
e.HasMorePages = True End If
End Sub
Figure 15.12
Previewing a simple document on the PrintPreview control
The static variable iPage is increased each time a new page is printed, and while it’s less than 8, the HasMorePages property is set to True, to continue printing. If you run the project at this point, you will see the first two pages on the PrintPreviewControl, but you have no way to zoom or jump to the following pages. The default magnification is set automatically, so that you can view the width of a page. To change the default magnification, you must set the Zoom property to the appropriate value. A value of 1 displays the document in actual size. The magnification you see will be something close to 0.3.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
738 Chapter 15 PRINTING WITH VB.NET
The Zoom In and Zoom Out buttons control the magnification. The Zoom In button increases the magnification by increasing the Zoom property by 25 percent. If the zoom value is more than 3 (three times the actual size), the Zoom property is clipped to 3.
Private Sub Button2_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Button2.Click
PrintPreviewControl1.Zoom = PrintPreviewControl1.Zoom * 1.25
If PrintPreviewControl1.Zoom > 3 Then PrintPreviewControl1.Zoom = 3
End Sub
Similarly, the Zoom Out button decreases the Zoom factor by 25 percent each time, down to a smallest magnification of 0.3:
Private Sub Button3_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Button3.Click
PrintPreviewControl1.Zoom = PrintPreviewControl1.Zoom / 1.25
If PrintPreviewControl1.Zoom < 0.3 Then PrintPreviewControl1.Zoom = 0.3
End Sub
The other two buttons allow you to move forward and backward through the pages. The current page on the preview pane is set by the StartPage property, so the other two buttons control the StartPage property. If the control displays multiple pages, the Page property is the number of the first page on the control. Our control displays two pages, so the StartPage property is increased or decreased by 2 (which is the value of the Columns property). If you set up a PrintPreview control with pages in multiple rows and columns, use the product of the Columns property times the Rows property. Here’s the code behind the two navigational buttons:
Private Sub bttnNext_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bttnNext.Click
PrintPreviewControl1.StartPage = _
PrintPreviewControl1.StartPage + PrintPreviewControl1.Columns
End Sub
Private Sub bttnPrevious_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bttnPrevious.Click
PrintPreviewControl1.StartPage = _
PrintPreviewControl1.StartPage - PrintPreviewControl1.Columns
End Sub
You may have noticed that the code doesn’t check the current value of the StartPage property. Even if you attempt to set this property to an invalid value, no exception will be thrown. The reason for this behavior is that we never know the number of the last page, so the control itself takes care of possible erroneous settings of the StartPage property.
The PrintPreview control exposes the UseAntiAlias property, which is a True/False value that indicates whether the control will use anti-aliasing in rendering the text. Set this property to True for the best possible preview, since the resolution of the screen (100 pixels or so per inch) is much lower than the resolution of a typical printer (600 to 1,200 dots per inch).
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |