|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
It all starts with a blank sheet of paperThe printing subsystem can be particularly daunting the first time it is encountered. It is unfamiliar to most developers, and it lacks the draw-and-code experience that the Windows Forms Designer has made so familiar to us. However there are a number of classes built in to the .NET framework that can make the whole experience a bit less of a chore... The print systemAlthough it is possible to live a happy and fulfilling life without ever looking under the bonnet at the print subsystem, it does make it slightly easier to write an application that has hardcopy capabilities if you have some understanding of what the Operating System does in response to the “print” command. The first thing an application needs to know in order to print is what print device to print to. To achieve this, it queries the spool server and asks it to return a list of the devices attached, and some basic information about them (name, location, device driver etc.). Then, the user selects one, and the application obtains a handle that refers to that printer, through which it queries the device settings (such as the paper size it uses, resolution etc.), and then it obtains a device context on which to draw the first page. Drawing the page is done with the standard GDI drawing commands such as Once the page is drawn, the application either notifies the spool system that the job is complete, or requests another page. At this stage, the drawn page can be translated into the printer control language appropriate to the printer by the printer driver, and the hardware can do its thing. In between pages, the application can also make changes to the settings of the printer so that, for example, one page can be printed landscape and the next portrait etc. Whenever the application or the printer performs an action on the print job, a notification is raised so that any application which monitors print jobs can be notified of their progress and so that any problems that occur printing the document can be notified to the user to rectify them. Printing in .NETPrinting in .NET follows the overview of the print system quite closely. There are two main framework classes that you use to do all your work with printing, which are in the Arguably, the best way of implementing a custom print operation in .NET is to create your own class that holds a private variable that is of type BeginPrintThe Private Sub PrintDocument_Form_BeginPrint(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintEventArgs)_
Handles PrintDocument_Form.BeginPrint
QueryPageSettingsThe Private Sub PrintDocument_Form_QueryPageSettings(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) _
Handles PrintDocument_Form.QueryPageSettings
If _LogicalPageNumber = 3 Then
e.PageSettings.Landscape = True
Else
e.PageSettings.Landscape = False
End If
End Sub
PrintPageAll of the actual printing on a page is done in the Private Sub PrintDocument_Form_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
Handles PrintDocument_Form.PrintPage
At the end of each page, you decide if there are more pages to print, set the EndPrintWhen the last page is printed (and you have told the print system that there are no more pages to follow), the Hints and tips
Worked exampleTo 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 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 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 ''' <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 ''' <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, Hooking the print up to a Windows formIn order to print and print preview this rudimentary document, we need to hook it up to a Windows form which has a The code to tie these three elements together is based on having a private instance of the Public Class Form1
Private MyRestaurantDoc As RestaurantDocument
'--8<--------------
To change the document settings, we show the 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 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: 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.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||