- •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 719
e.Graphics.ResetTransform() e.Graphics.TranslateTransform(Tx, Ty) e.Graphics.RotateTransform(90)
e.Graphics.DrawString(“GDI+ Graphics (90)”, fnt, Brushes.Black, 0, 0) RectSize = e.Graphics.MeasureString(“GDI+ Graphics (90)”, fnt)
Rect = New Rectangle(0, 0, RectSize.Width, RectSize.Height) e.Graphics.DrawRectangle(Pens.Green, Rect)
‘Print string rotated 270 degrees e.Graphics.ResetTransform() e.Graphics.TranslateTransform(Tx, Ty) e.Graphics.RotateTransform(270)
e.Graphics.DrawString(“GDI+ Graphics (270)”, fnt, Brushes.Black, 0, 0) RectSize = e.Graphics.MeasureString(“GDI+ Graphics (270)”, fnt)
Rect = New Rectangle(0, 0, RectSize.Width, RectSize.Height) e.Graphics.DrawRectangle(Pens.Green, Rect)
‘Print string rotated 180 degrees
e.Graphics.ResetTransform() e.Graphics.TranslateTransform(Tx, Ty) e.Graphics.RotateTransform(180)
e.Graphics.DrawString(“GDI+ Graphics (180)”, fnt, Brushes.Black, 0, 0) RectSize = e.Graphics.MeasureString(“GDI+ Graphics (180)”, fnt)
Rect = New Rectangle(0, 0, RectSize.Width, RectSize.Height) e.Graphics.DrawRectangle(Pens.Green, Rect)
End Sub
As you know by now, to activate the PrintPage event handler, you must call the Print method of the PrintDocument object or display the Print Preview dialog box by calling its ShowDialog method. The following statements display the rotated strings on a Print Preview dialog box:
PrintPreviewDialog1.Document = PrintDocument1
PrintPreviewDialog1.UseAntiAlias = True
PrintPreviewDialog1.ShowDialog()
Printing Examples
Using the Framework’s printing objects is straightforward, in principle. Depending on the type of the printout you want to generate, however, the code of the PrintPage event handler can get quite complicated. Since there are no techniques that you can apply to all situations, I’ve included a few typical examples to demonstrate how to use the same objects to perform very different tasks. The first example demonstrates how to print tabular reports. A tabular report has the form of a grid, with columns of different width and rows of different height.
The second example is the printing of text and, even though this is the least exciting type of printout, you should be able to send text to the printer. As you will see, it’s not a trivial operation. The last example prints bitmaps, probably the simplest type of printout. The only challenge with printing bitmaps is that you may have to reduce the size of the bitmap to make it fit in the width, or the height, of the page.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
720 Chapter 15 PRINTING WITH VB.NET
Printing Tabular Data
This is the printing operation you’ll be using most often in typical business applications that require custom printing. Figure 15.7 shows an example of a printout with tabular data. This printout was generated by the PrintTable project, which you can find in this chapter’s folder on the CD, and its code is discussed in detail here.
The ISBN column contains a 10-character string, and it’s quite simple to handle. All you have to do is make sure that the ISBN will fit in the corresponding column. If you allow the user to select the font at runtime and you can’t set a fixed width for this column, you should print only as many characters as will fit in the reserved width. In this example, we aren’t going to do anything special about the ISBN column.
Figure 15.7
Using the PrintTable application to print data in a tabular arrangement
The Title column has a variable length, and you may have to break long titles into two or more printed lines—and this is the real challenge of this application. As you recall from the discussion of the DrawString method in Chapter 14, this method can print a string in a rectangle you pass as an argument. The width of this rectangle must be the same as the width of the Title column. The height of the rectangle should be enough for the entire text to fit in it. In our code, we’ll use a rectangle with the appropriate width and adequate height to make sure that the entire title will be printed. Alternatively, you can trim the title if it’s too long, but there’s no point in trimming substantial information.
Of course, depending on its length, the title may take up one, two, or even more lines on the page. You must also keep track of the height of the title’s cell and take it into consideration in printing the next row of the table.
The last intricacy of this application is the Authors column. Each book may have no authors or one or more authors, and we’ll print each author on a separate line. As you realize, the total height of
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
PRINTING EXAMPLES 721
each row depends on the height of the Title or Author cell. We must keep track of the height of these two cells and move down accordingly before printing the following row. Where the height of the Authors cells is determined by the number of authors—we’ll print each author on a single line and assume that the name does not exceed the width of the page—we must provide the code to break the title into multiple lines.
So, where does the data come from? It could come from a text file, an XML document, or a database. It doesn’t really make a difference, as long as you can access one row at a time and extract its fields. For the purposes of this example, and since we haven’t discussed databases yet, I’m using a ListView control to store the data. The ListView control is populated in the form’s Load event handler. Each book is a different item in the ListView, and the various fields are subitems. The main item’s Text property is the book’s ISBN, and the remaining fields are stored as subitems. I will not show the code that populates the ListView control here, just the statements that populate the first two items. I’ve taken sample data from an online bookstore and, in some cases, edited their titles to make them long or added fictitious authors. For all intents and purposes, the data used in this sample application should be considered fictitious.
Dim BookItem As New ListViewItem()
BookItem.Text = “0393049515”
BookItem.SubItems.Add(“The Dream of Reason: “ & _
“A History of Philosophy from the Greeks to the Renaissance”)
BookItem.SubItems.Add(“Anthony Gottlieb”)
ListView1.Items.Add(BookItem)
BookItem = New ListViewItem()
BookItem.Text = “0156445085”
BookItem.SubItems.Add(“In Search of the Miraculous: “ & _
“Fragments of an Unknown Teaching”)
BookItem.SubItems.Add(“P. D. Ouspensky”)
ListView1.Items.Add(BookItem)
You can open the PrintTable project on the CD and examine the code of the button that populates the ListView control. Once the list has been populated, you can click the Preview & Print button to generate the preview and print the report. The main form of the PrintTable project, populated with the data shown in the sample printout, is shown in Figure 15.8.
Figure 15.8
The PrintTable project’s main form
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
722 Chapter 15 PRINTING WITH VB.NET
Formatting the Cells
The report is generated one row at a time. The vertical coordinate of the row is stored in the variable Y, which is incremented accordingly for each new row. This coordinate applies to all cells, and if a cell contains multiple lines, the y coordinate is adjusted accordingly for each line. The x coordinate of each column is the same for all rows. These coordinates are calculated at the beginning and they don’t change from row to row.
Breaking a string into multiple lines isn’t trivial. You should include as many words as you can on each line without exceeding the available width. Fortunately, the Graphics object’s MeasureString method can break a string into the required number of lines to fit the string into a rectangle and report the number of lines. This form of the MeasureString method is
Graphics.MeasureString(string, font, size, format, cols, lines)
The first argument is the string to be printed, and it will be rendered in the font specified by the second argument. The size argument is the width and height of the rectangle in which the string must fit. In our case, the width of the size argument is the width of the cell in which the string must fit. The last two arguments are the number of characters that will fit across the rectangle and the number of lines the string must be broken into. Even though we don’t know the height of the rectangle in advance, we can use an absurdly large value. The MeasureString method will tell us how many text lines it needs, and we’ll use this value to calculate the height of the rectangle. To calculate the height of the cell in which the title will fit, the program uses the following statements:
Dim cols, lines As Integer
e.Graphics.MeasureString(strTitle, tableFont, New SizeF(W2, 100), _ New StringFormat(), lines, cols)
strTitle is a string variable that holds the title, and tableFont is the font in which the string will be rendered. W2 is the width of the second column of the grid, where the title appears. This is a fixed value, calculated ahead of time. The initial height of the rectangle is 100 pixels, and we hope that even the longest title will fit in this rectangle. You can make the cell even taller, but this sample project will work as advertised with reasonably sized fields. It is possible for a given cell’s text to be so long that it will take a page and a half to print. The PrintTable project can’t handle similar extreme situations. You will have to provide additional code to handle the overflow of a cell to the following page.
The lines and cols variables are passed by reference, and they are set by the MeasureString method to the number of lines and number of characters that will fit in the specified rectangle. The exact location of the rectangle doesn’t make any difference; only its dimensions matter, and that’s why the third argument is a SizeF object and not a Rectangle object.
Once we have the number of lines it takes for the title to be printed in the specified width, we can advance the vertical coordinate by the following amount:
lines * tableFont.GetHeight(e.Graphics)
tableFont is the font we use to print the table. Its GetHeight method returns the height of the font when rendered on the Graphics object passed as argument. This will take care of breaking long titles into multiple lines, which is the most challenging aspect of the code. The last cell in each row contains
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
PRINTING EXAMPLES 723
a line for each author. The following loop goes through all the authors and prints them, each one on a separate line:
For subitm = 2 To ListView1.Items(itm).SubItems.Count - 1 str = ListView1.Items(itm).SubItems(subitm).Text
e.Graphics.DrawString(str, tableFont, Brushes.Black, X3, Yc) Yc = Yc + tableFont.Height + 2
Next
The y coordinate of the last author is stored in the variable Yc. To calculate the y coordinate of the next row of the table, we compare the Y and Yc variables and keep the larger value. This value, plus a small displacement, is used as the y coordinate for the following line. Listing 15.7 is the complete listing of the PrintPage event handler of the PrintTable project.
Listing 15.7: The PrintPage Event Handler of the PrintTable Project
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _ Handles PrintDocument1.PrintPage
Y = PrintDocument1.DefaultPageSettings.Margins.Top + 20 e.Graphics.DrawString(“ISBN”, TitleFont, Brushes.Black, X1, Y) e.Graphics.DrawString(“Title”, TitleFont, Brushes.Black, X2, Y) e.Graphics.DrawString(“Author(s)”, TitleFont, Brushes.Black, X3, Y) Y = Y + 30
While itm < ListView1.Items.Count Dim str As String
str = ListView1.Items(itm).Text
e.Graphics.DrawString(str, tableFont, Brushes.Black, X1, Y) str = ListView1.Items(itm).SubItems(1).Text
Dim R As New RectangleF(X2, Y, W2, 80) e.Graphics.DrawString(str, tableFont, Brushes.Black, R) Dim lines, cols As Integer
e.Graphics.MeasureString(str, tableFont, New SizeF(W2, 50), _ New StringFormat(), cols, lines)
Dim subitm As Integer, Yc As Integer Yc = Y
For subitm = 2 To ListView1.Items(itm).SubItems.Count - 1 str = ListView1.Items(itm).SubItems(subitm).Text
e.Graphics.DrawString(str, tableFont, Brushes.Black, X3, Yc) Yc = Yc + tableFont.Height + 2
Next
Y = Y + lines * tableFont.Height + 5 Y = Math.Max(Y, Yc)
With PrintDocument1.DefaultPageSettings e.Graphics.DrawLine(Pens.Black, .Margins.Left, Y, _
.PaperSize.Width - .Margins.Right, Y) If Y > 0.95 * (.PaperSize.Height - .Margins.Bottom) Then
e.HasMorePages = True
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
724 Chapter 15 PRINTING WITH VB.NET
Exit Sub End If
End With
itm = itm + 1 End While
e.HasMorePages = False End Sub
The code makes use of a few variables that are declared on the Form level with the following statements:
Dim tableFont, titleFont As Font
Dim X1, X2, X3 As Integer
Dim W1, W2, W3 As Integer
Dim Y As Integer
Dim itm As Integer
Before we can print, we must specify the widths of the columns. Since we know the information we’re going to display in each column, we can make a good estimate of the column widths. The first column, where the ISBN is displayed, starts at the left margin of the page and extends 100 units to the right. The default unit is 1/100 of an inch, so the ISBN column’s width is 1 inch. The title column should take up most of the page’s width. In the PrintTable example, I’ve given 50 percent of the available page width to this column. The remaining space goes to the Author column. The variables X1, X2, and X3 are the x coordinates of the left edge of each column, while the variables W1, W2, and W3 are the widths of the columns. These variables are set in the Print button’s Click event handler. Then, the subroutine displays the PrintPreview dialog box to display the document, as it will be printed on the page. Listing 15.8 shows the Print button’s Click event handler.
Listing 15.8: Setting Up the Columns and Printing the Table
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click PageSetupDialog1.PageSettings = PrintDocument1.DefaultPageSettings If PageSetupDialog1.ShowDialog() Then
PrintDocument1.DefaultPageSettings = PageSetupDialog1.PageSettings End If
tableFont = New Font(“Arial”, 8)
titleFont = New Font(“Arial”, 12, FontStyle.Bold) X1 = PrintDocument1.DefaultPageSettings.Margins.Left Dim pageWidth As Integer
With PrintDocument1.DefaultPageSettings
pageWidth = .PaperSize.Width - .Margins.Left - .Margins.Right End With
X2 = X1 + 100
X3 = X2 + pageWidth * 0.5
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
PRINTING EXAMPLES 725
W1 = X2 - X1
W2 = X3 - X2
W3 = pageWidth - X3 PrintPreviewDialog1.Document = PrintDocument1 PrintPreviewDialog1.ShowDialog()
itm = 0 End Sub
The global variables are set in the Print button’s Click event handler, but they’re all declared outside any procedure, because they must be accessible by the PrintPage event handler. After setting the variables, you can call the ShowDialog method of the PrintPreviewDialog control to preview the document.
The PrintPage event is fired whenever a new page must start. First, we print the header of the table with the following statements:
Y = PrintDocument1.DefaultPageSettings.Margins.Top + 20 e.Graphics.DrawString(“ISBN”, titleFont, Brushes.Black, X1, Y) e.Graphics.DrawString(“Title”, titleFont, Brushes.Black, X2, Y) e.Graphics.DrawString(“Author(s)”, titleFont, Brushes.Black, X3, Y) Y = Y + 30
titleFont is a Font object that represents the font we use for the table header and is declared on the Form level. The rest of the program uses the tableFont object, which represents the font in which the table’s text will be rendered. Here are the declarations of these two objects:
Dim tableFont As Font
tableFont = New Font(“Arial”, 8) Dim titleFont As Font
titleFont = New Font(“Arial”, 12, FontStyle.Bold)
Then we set up two nested loops. The outer loop goes through all the items on the ListView control, and the inner loop goes through the subitems of the current item. The structure of the two loops is the following:
While itm < ListView1.Items.Count { print current item }
For subitm = 2 To ListView1.Items(itm).SubItems.Count - 1 { print all subitems }
Next
End While
The PrintTable project is based on the assumption that the author names will fit in the specified width. If not, part of the author name will flow over the right margin. You can either break long author names (similar to breaking the title into multiple lines) or truncate author names. If you want to print a box around the report, you must definitely truncate the author names, so that they won’t run over the right margin. Alternatively, you can print the report in landscape mode—you may have to adjust the widths of the Title and Author columns.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |