Microsoft & .NET.NETA .NET Text Printing Class... That Works!

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.

# # #

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories