A .NET Text Printing Class... That Works!
You can print from your program in a number of ways. One option, for example, is to automate Microsoft Word, edit a document in code, then programmatically print it out.
However, if you're looking to print directly from your application, the .NET Framework provides a number of components to help you in the System.Drawing.Printing namespace.
The core component here is PrintDocument. At its simplest, printing involves instantiating a PrintDocument object, setting its properties, and calling the Print method. With each page to be printed, the PrintDocument raises a PrintPage event, to which you need to add your own printing logic. Other key classes in the same Printing namespace include PrinterSettings, PageSettings, and PrintPreviewControl.
As you can imagine, this is a large area and can get relatively complex. The following class attempts to simplify one of the most common uses: the simple printing of text. Simply add the following class code to your project and use as directed.
It's worth noting that this class actually works, as opposed to the less-functional TextFilePrintDocument class bundled by Microsoft in the Windows Forms QuickStart tutorials, which cuts out as soon as a blank line is encountered in the passed text file, prints over the margin if a line is too large, plus only reads text from files. It is also neatly encapsulated and allows you to change its Font through a simple property, unlike Microsoft's second attempt with its "101 VB.NET Samples".
Here's the code:
Public Class TextPrint ' Inherits all the functionality of a PrintDocument Inherits Printing.PrintDocument ' Private variables to hold default font and text Private fntPrintFont As Font Private strText As String Public Sub New(ByVal Text As String) ' Sets the file stream MyBase.New() strText = Text End Sub Public Property Text() As String Get Return strText End Get Set(ByVal Value As String) strText = Value End Set End Property Protected Overrides Sub OnBeginPrint(ByVal ev _ As Printing.PrintEventArgs) ' Run base code MyBase.OnBeginPrint(ev) ' Sets the default font If fntPrintFont Is Nothing Then fntPrintFont = New Font("Times New Roman", 12) End If End Sub Public Property Font() As Font ' Allows the user to override the default font Get Return fntPrintFont End Get Set(ByVal Value As Font) fntPrintFont = Value End Set End Property Protected Overrides Sub OnPrintPage(ByVal ev _ As Printing.PrintPageEventArgs) ' Provides the print logic for our document ' Run base code MyBase.OnPrintPage(ev) ' Variables Static intCurrentChar As Integer Dim intPrintAreaHeight, intPrintAreaWidth, _ intMarginLeft, intMarginTop As Integer ' Set printing area boundaries and margin coordinates With MyBase.DefaultPageSettings intPrintAreaHeight = .PaperSize.Height - _ .Margins.Top - .Margins.Bottom intPrintAreaWidth = .PaperSize.Width - _ .Margins.Left - .Margins.Right intMarginLeft = .Margins.Left 'X intMarginTop = .Margins.Top 'Y End With ' If Landscape set, swap printing height/width If MyBase.DefaultPageSettings.Landscape Then Dim intTemp As Integer intTemp = intPrintAreaHeight intPrintAreaHeight = intPrintAreaWidth intPrintAreaWidth = intTemp End If ' Calculate total number of lines Dim intLineCount As Int32 = _ CInt(intPrintAreaHeight / Font.Height) ' Initialise rectangle printing area Dim rectPrintingArea As New RectangleF(intMarginLeft, _ intMarginTop, intPrintAreaWidth, intPrintAreaHeight) ' Initialise StringFormat class, for text layout Dim objSF As New StringFormat(StringFormatFlags.LineLimit) ' Figure out how many lines will fit into rectangle Dim intLinesFilled, intCharsFitted As Int32 ev.Graphics.MeasureString(Mid(strText, _ UpgradeZeros(intCurrentChar)), Font, _ New SizeF(intPrintAreaWidth, _ intPrintAreaHeight), objSF, _ intCharsFitted, intLinesFilled) ' Print the text to the page ev.Graphics.DrawString(Mid(strText, _ UpgradeZeros(intCurrentChar)), Font, _ Brushes.Black, rectPrintingArea, objSF) ' Increase current char count intCurrentChar += intCharsFitted ' Check whether we need to print more If intCurrentChar < strText.Length Then ev.HasMorePages = True Else ev.HasMorePages = False intCurrentChar = 0 End If End Sub Public Function UpgradeZeros(ByVal Input As Integer) As Integer ' Upgrades all zeros to ones ' - used as opposed to defunct IIF or messy If statements If Input = 0 Then Return 1 Else Return Input End If End Function End Class
We could use this class as follows:
' Create object, passing in text Dim MyPrintObject As New TextPrint(TextBox1.Text) ' Set font, if required MyPrintObject.Font = New Font("Tahoma", 8) ' Issue print command MyPrintObject.Print()
About the Author
Karl Moore (MCSD, MVP) is an experience author living in Yorkshire, England. He is author of numerous technology books, including the new Ultimate VB .NET and ASP.NET Code Book (ISBN 1-59059-106-2), plus regularly features at industry conferences and on BBC radio. Moore also runs his own creative consultancy, White Cliff Computing Ltd. Visit his official Web site at www.karlmoore.com.
# # #