Hints and tips
- Graphics measurements in printing are in tenths of a millimeter - e.g., to print a rectangle 4 x 5 centimeters, you would use e.Graphics.DrawRectangle(Pens.Black, 10, 10, 4000, 5000)
- Z-Order (such as it is) is defined by the order that the print commands are issued - i.e., later drawing commands print on top of earlier ones
Worked example
To illustrate this, the following is a "quick and dirty" worked example that is a restaurant guide. The data source for this is an XML data set thus:-
<?xml version="1.0" encoding="utf-8" ?>
<!-- The list of restaurants -->
<RestaurantMenu xmlns="http://tempuri.org/RestaurantMenu.xsd">
<Restaurant>
<Name>MV Cillairne</Name>
<Address_1 > North Wall Quay </Address_1>
<Address_2 > Docklands, Dublin 1 </Address_2>
<Logo_Image >D:\Users\Duncan\Documents\Presentations\
Hardcore Hardcopy\RestaurantMenuPrinter\RestaurantMenuPrinter\
Images\mvcillairne.bmp</Logo_Image>
</Restaurant>
To print out this data, we create a new class that inherits from PrintDocument:
VB Code:
Public Class RestaurantDocument
Inherits System.Drawing.Printing.PrintDocument
To print this record set, we need a record pointer (to know where we are in the data set) and a couple of fonts to print the data with. These are going to be set up in the BeginPrint event and used in the PrintPage event, so are declared at class level:
VB Code:
Private _restaurantDataSet As DataSet
Private _currentPage As Integer = 0
Private _currentRecord As Integer = 0
Private _titleFont As Font
Private _detailFont As Font
and are initialised in the BeginPrint event:
VB Code:
''' <summary />
''' The BeginPrint event is raised when the print job is initiated.
''' You should use this event to do any setting up that will be
''' required to perform the print job
''' </summary />
Private Sub RestaurantDocument_BeginPrint(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintEventArgs) _
Handles Me.BeginPrint
'\\ Create the font objects we are going to print with
_titleFont = New Font(FontFamily.GenericSerif, 16, _
FontStyle.Bold, GraphicsUnit.Point)
_detailFont = New Font(FontFamily.GenericSerif, 9, _
FontStyle.Regular, GraphicsUnit.Point)
End Sub
For each page in the restaurant guide, we print the restaurant name, logo, and address. Text elements are printed using the Graphics.DrawString command, and images using the Graphics.DrawImage command:
VB Code:
''' <summary />
''' The PrintPage event is called once for each page to print
''' </summary />
''' <remarks />
''' Set e.HasMorePages to true to print more pages
''' </remarks />
Private Sub RestaurantDocument_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
Handles Me.PrintPage
With _restaurantDataSet.Tables(0).Rows(_currentRecord)
'\\ Print the restaurant name
e.Graphics.DrawString(.Item("Name").ToString, _
_titleFont, Brushes.Black, 20, 20)
Dim yPos As Single = 100
'\\ Print the restaurant image
If (.Item("Logo_Image").ToString <> "") Then
Dim fiImage As New _
System.IO.FileInfo(.Item("Logo_Image").ToString)
Dim img As New Bitmap(fiImage.FullName)
e.Graphics.DrawImage(img, 20, 60)
yPos += img.Height
End If
'\\ Print the restaurant address details
e.Graphics.DrawString(.Item("Address_1").ToString, _
_detailFont, Brushes.Black, 20, yPos)
yPos += e.Graphics.MeasureString(.Item("Address_1").ToString, _
_detailFont).Height
e.Graphics.DrawString(.Item("Address_2").ToString, _
_detailFont, Brushes.Black, 20, yPos)
yPos += e.Graphics.MeasureString(.Item("Address_2").ToString, _
_detailFont).Height
e.Graphics.DrawString(.Item("Telephone").ToString, _
_detailFont, Brushes.Black, 20, yPos)
End With
_currentRecord += 1
If (_currentRecord < _restaurantDataSet.Tables(0).Rows.Count) Then
e.HasMorePages = True
_currentPage += 1
End If
End Sub
And, Graphics.MeasureString is used to correctly space the address lines underneath each other.
Hooking the print up to a Windows form
In order to print and print preview this rudimentary document, we need to hook it up to a Windows form which has a PrintDialog and a PrintPreviewDialog component on it and three menu items: Print Preview, Print, and also Document Properties.
The code to tie these three elements together is based on having a private instance of the RestaurantDocument class in the form code:
VB Code:
Public Class Form1
Private MyRestaurantDoc As RestaurantDocument
'--8<--------------
To change the document settings, we show the PrintDialog dialog box:
VB Code:
Private Sub DocumentSettingsToolStripMenuItem_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles DocumentSettingsToolStripMenuItem.Click
If Me.PrintDialog_Restaurant.ShowDialog = Windows.Forms.DialogResult.OK Then
MyRestaurantDoc.PrinterSettings = Me.PrintDialog_Restaurant.PrinterSettings
End If
End Sub
To preview the document, we need to show the PrintPreviewDialog component dialog box:
VB Code:
Private Sub PrintPreviewDialog_Restaurant_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles PrintPreviewToolStripMenuItem.Click
PrintPreviewDialog_Restaurant.Document = MyRestaurantDoc PrintPreviewDialog_Restaurant.ShowDialog()
End Sub
and lastly, (and indeed most simple of all) to print the document to a printer:
VB Code:
Private Sub PrintToolStripMenuItem_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles PrintToolStripMenuItem.Click
MyRestaurantDoc.Print()
End Sub
I hope this article gives you enough insight to allow you to approach the .NET printing subsystem. Once you do, you will find it is a very powerful part of the framework which will help in producing more fully featured Windows applications.