The VBPrint Project
This solution's example consists of two projects: a PRNClass project, which is a class, and a test project. The PRNClass project contains the LVPrint class and a blank form that serves as the preview surface. Compiling the class project creates a DLL which you can use with any other project. The preview form is displayed automatically from within the class's code as needed. All the printing and previewing functionality is cast into a DLL, which can handle any ListView. Keep in mind that the LVPrint class expects that the ListView control has a Columns collection. If you don't set up the control's Columnscollection, nothing will be printed.
The Printing Code
First, you need to understand the role of the form-level variables, which are used by multiple procedures in the application. These variables are declared at the form's level with the following statements:
' Work variables
Dim PRN As Object
Dim XPos As Single, YPos As Single
Dim RowHeight As Single
Dim CellHeight As Single
Dim YMin As Single, YMax As Single
Dim MorePages As Boolean
Dim currentRow As Integer
Dim colWidths() As Single
The PRN variable represents the printing surface (the preview form, or the actual page). For more information on printing and previewing see the first installationof the series. XPos and YPos are the coordinates of the next element that will be printed on the page. Every time the code prints a cell, it adjusts the settings of these two variables for the next cell on the same row, or the following row. YMin and YMax are the coordinates of the top and bottom of the printable area on the page.
RowHeight is the default height of a row (a row that contains cells that don't span multiple text lines). CellHeight is the current row's height. CellHeight is larger that RowHeight for rows with cells that span multiple lines of text. Every time the code prints a cell, it adjusts the value of the CellHeight variable. Basically, this variable keeps track of the vertical space between consecutive rows. The MorePages variable is a Boolean variable that determines whether there are more pages to be printed when the end of the current page is reached. The currentRow variable holds the index of the row being printed and is increased by one after printing a row of cells. colWidths, finally, is an array that holds the widths of the printout's columns. The widths of printout's columns are proportional to the widths of the columns of the ListView control. The printout's width is the width of the page minus the margins. The available width on the page is split among the columns proportionally to the width of each column on the ListViewcontrol.
The PrintList Method
The PrintList method starts by displaying the Print common dialog box, where the user can select the printer and set the printout's orientation. Then it sets the printer's font to the same font as the one used to render the items on the ListView control and the margins by calling the SetMargins subroutine. The margins are hardcoded in the sample application, but you can easily design a dialog box to prompt the user for the margin values. It continues by calculating the width each column should have on the printed page. Because the page's width (or height, if you're printing in landscape mode) is different from the window's width on the screen, you must resize the columns so that they fill the width (or height) of the page. These calculations take place in the CalculateColumnWidthssubroutine.
Finally, the code prints the ListView item's on the page. This takes place from within a While loop that prints one page at a time, as long as there pages to be printed (variable MorePages). First it prints the column headers by calling the PrintListViewHeaders subroutine and then calls the PrintListView subroutine, which prints as many items as it can fit on the current page. When the end of the page is reached, the code emits the current page, sets the MorePagesvariable to True and exits.
Here's the PrintList subroutine, which calls the various subroutines to perform the basic printing operations. The actual project contains more code, as well as extensive comments, but this is a fairly substantial outline of the PrintListsubroutine:
Printing the ListView control
Public Function PrintList(ByVal preview As Boolean) As Boolean
Dim frm As New frmPreview
Dim CD As mscomdlg.CommonDialog
Set CD = frmPreview.CommonDialog1
If CD.Orientation = cdlLandscape Then
Printer.Orientation = cdlLandscape
Printer.Orientation = cdlPortrait
If preview Then
Set PRN = frmPreview
Set PRN = Printer
If PRN Is Nothing Then
If PRN Is frmPreview Then
MorePages = True
currentRow = 0
While MorePages And currentRow < LV.listitems.Count
If PRN Is frmPreview Then
XPos = LeftMargin: YPos = TopMargin
PRN.CurrentX = XPos: PRN.CurrentY = YPos
If PrintListViewHeaders = False Then
PrintList = False
PrintList = True
As you can see, most of the procedures used by the LVPrint class are implemented as functions and they return a True/False value. The printing job may fail at several places and the code examines each function's return value upon completion. If False, the job must terminate. If the PrintListViewHeaders function returns False, then the PrintListsubroutine terminates and returns False to indicate that the printout failed.