UserGuide

Printing

From Xojo Documentation

For desktop apps, printing is very similar to drawing to the screen. But instead of drawing into a Graphics object of a Canvas control, you draw to a Graphics object created specifically for printing. There are methods available to allow you to create new pages and get printer settings.

For web apps, printing is far more limited. Usually what works best is to create HTML, display it in an UserGuide:Web HTML Viewer control and then print that.

Desktop Printing

Printer Settings

Before printing anything, you usually want to give the user the ability to select the printer they want to use. This is done using the PrinterSetup class, which displays the Page Setup dialog for the operating system. In addition, this class returns the settings so that you can use them again later without prompting the user.

// PrinterSettings is a String property on the Window
Dim ps As New PrinterSetup
ps.SetupString = mPrinterSettings

If ps.PageSetupDialog Then
PrinterSettings = ps.SetupString
End If

Since PrinterSettings is a String, you can save it outside of your app (such as in a database or a file) for use the next time the user prints.

The PrinterSetup class has properties for printer settings such as landscape, page size and resolution. The Language Reference topic for PrinterSetup has more details on these properties.

PrinterSetup is not supported in Linux apps.

Printing Text and Graphics

To print text and graphics you draw to the Graphics object for the printer. To get this Graphics objects, you call either the OpenPrinterDialog or OpenPrinter global methods. The only difference between these two methods is that one displays the Print dialog and the other does not. Since the printing system on MacOS has the automatic capability to print to PDF, you can use this method to easily generate PDF files. On Windows you can install a "Print to PDF" printer driver to enable sending printed output to PDF files.

Since you are drawing to a Graphics object, all the commands covered in the UserGuide:Pictures, Images and Graphics topic can be used.

In addition, you also use the printing-specific method, NextPage to create multiple pages. This code prints “Hello” on page 1 and “World” on page 2:

Dim ps As New PrinterSetup
If ps.PageSetupDialog Then
Dim page As Graphics
page = OpenPrinterDialog(ps)
If page <> Nil Then
// Draw text on page 1 with 1 inch left/top margin
page.DrawString("Hello", ps.HorizontalResolution, ps.VerticalResolution)
page.NextPage
// Draw text on page 2 with 1 inch left/top margin
page.DrawString("World", ps.HorizontalResolution, ps.VerticalResolution)
End If
End If

You can also use any printer settings that were previously stored from using the PrinterSetup class.

Dim ps As New PrinterSetup
ps.SetupString = PrinterSettings // Property containing previously saved settings

If ps.PageSetupDialog Then
PrinterSettings = ps.SetupString // Get new settings

Dim page As Graphics
// Use Printer Settings
page = OpenPrinterDialog(ps)
If page <> Nil Then
// Draw text on page 1 with 1 inch left/top margin
page.DrawString("Hello", ps.HorizontalResolution, ps.VerticalResolution)
page.NextPage
// Draw text on page 2 with 1 inch left/top margin
page.DrawString("World", ps.HorizontalResolution, ps.VerticalResolution)
End If
End If

Each time you call NextPage, the current page is sent to the printer and the graphics object (in this case page) is cleared so that you can immediately begin drawing the new content. The final page gets sent to the printer when the page goes out of scope.

To print without displaying the Printer dialog, you call the OpenPrinter method:

Dim ps As New PrinterSetup
Dim page As Graphics
page = OpenPrinter(ps)
If page <> Nil Then
// Draw text on page 1 with 1 inch left/top margin
page.DrawString("Hello", ps.HorizontalResolution, ps.VerticalResolution)
page.NextPage
// Draw text on page 2 with 1 inch left/top margin
page.DrawString("World", ps.HorizontalResolution, ps.VerticalResolution)
page.NextPage
End If

Printing Multiple Pages of Text

To print multiple pages, you need to parse each line and print it if it will fit on the page. If it will not fit, then you call NextPage so that your text will start printing at the top of the next page.

A common thing to do is to split the text into paragraphs and then track the height of the page and the height of the next paragraph to print to make sure that it will fit onto the page. If it will not fit, then the current page is sent to the printer and a new page is created to start printing the next paragraph.

This code shows you how you can print text from a TextArea onto multiple pages:

Dim ps As New PrinterSetup
If ps.PageSetupDialog Then
Dim page As Graphics
page = OpenPrinterDialog(ps)
If page <> Nil Then
// Draw text on page 1 with 1 inch left/top margin
Dim leftMargin As Double = ps.HorizontalResolution
Dim topMargin As Double = ps.VerticalResolution
page.TextSize = Val(FontPopup.Text)

// To print multiple pages, you need to parse each line and print it
// if it will fit on the page. If it will not fit, then
// you call NextPage so that your text will start printing at the top
// of the next page.

// First, split the text into multiple paragraphs
Dim paragraphs() As String = ReplaceLineEndings(TextArea1.Text, EndOfLine).Split(EndOfLine)

Dim pageTextHeight As Double = topMargin
Dim newpageTextHeight As Double
Dim lineWidth As Double

For i As Integer = 0 To paragraphs.Ubound
newpageTextHeight = pageTextHeight + page.StringHeight(paragraphs(i), ps.Width - leftMargin * 2)

If newPageTextHeight > ps.Height - topMargin * 2 Then
// String does not fit on page, so move to next page
page.NextPage
pageTextHeight = topMargin
newpageTextHeight = pageTextHeight + page.StringHeight(paragraphs(i), ps.Width - leftMargin * 2)
End If
// If string fits on page, then draw it
page.DrawString(paragraphs(i), leftMargin, pageTextHeight, ps.Width - leftMargin * 2)
// Keep a cumulative count of the pageheight as strings are added to it
pageTextHeight = newpageTextHeight // Adjust page text height
pageTextHeight = pageTextHeight + topMargin / 8 // 1/8 inch between paragraphs
Next
End If
End If

The above code gives you a lot of control, but it is more work to track everything yourself. In the next section you'll see how you can take advantage of StyledTextPrinter to make this easier.

Printing Styled Text

Because TextAreas are capable of displaying styled text and multiple font sizes, you will usually want to retain the styled text when you print. The StyledTextPrinter class is used for this purpose, using the DrawBlock method.

The StyledTextPrinter class only works with MacOS apps.

To print styled text, you first create a StyledTextPrinter object and then call the StyledTextPrinter method of the TextArea (specifying the graphics to use and the width of the text) to get an instance of a StyledTextPrinter that can be used for printing.

With this instance, you can call the DrawBlock method to draw the styled text to the page (specifying the starting coordinates and the height).

This code prints styled text in a TextArea:

Dim stp As StyledTextPrinter
Dim g As Graphics
Dim p As New PrinterSetup

If p.PageSetupDialog Then
g = OpenPrinterDialog(p)

If g <> Nil Then
// Set width as 7.5 inches
stp = PrintTextArea.StyledTextPrinter(g, 7.5 * p.HorizontalResolution)
Do Until stp.EOF
// Fill the page with text
// at 10 inches height
stp.DrawBlock(0, 0, 10 * p.VerticalResolution)
If Not stp.EOF Then
// There is more text, so add a page
g.NextPage
End If
Loop
End If
End If

In order to support styled printing, the Text Area must have both its Multiline and Styled properties ON (True).

If the text to print is larger than what will fit in the specified block, then you can iterate through the text until it is all printed. You do this by checking the EOF property of the StyledTextPrinter class after each call to DrawBlock.

This code prints the contents of a Text Area into two columns with a quarter inch spacing between the columns:

Dim g As Graphics
Dim p As New PrinterSetup

If p.PageSetupDialog Then
g = OpenPrinterDialog(p)

// 1 inch margin
Dim leftRightMargin As Double = 1 * p.HorizontalResolution
Dim topBottomMargin As Double = 1 * p.VerticalResolution

// Page width after accounting for margins
Dim pageWidth As Double = p.Width - (leftRightMargin * 2)

// Column gap is 1/4 of the margin (so, 1/4 inch)
Dim columnGap As Double = leftRightMargin / 4

// Calculate the column width
// Subtract column gap from page with and
// split result 2
Dim columnWidth As Double = (pageWidth - columnGap) / 2

// Page size after accounting for margins
Dim pageHeight As Double = p.Height - (topBottomMargin * 2)

Dim stp As StyledTextPrinter
stp = PrintTextArea.StyledTextPrinter(g, pageWidth)
stp.Width = columnWidth

Dim columnToPrint As Integer = 1
Do Until stp.EOF
stp.DrawBlock(leftRightMargin + (columnWidth + columnGap) * (columnToPrint - 1), _
topBottomMargin, pageHeight)
If columnToPrint = 2 Then // printing last column
If Not stp.EOF Then // more text to print
g.NextPage
columnToPrint = 1
End If
Else // more columns to print on this page
columnToPrint = columnToPrint + 1
End If
Loop
End If

HTML Printing

Another technique you can use is to create what you want to print using HTML, display it in an HTMLViewer and then call its print method. This can sometimes be useful for simple reports. As a simple example, this code loads an HTMLViewer with some HTML:

Dim html As String = "<html><body><em>Hello</em>, World!</body></html>"
HTMLViewer1.LoadPage(html, GetTemporaryFolderItem)

This code then displays the print dialog for the user to print the HTML:

HTMLViewer1.Print(True)

Web Printing

Web printing is considerably simpler than desktop printing because it is much more restricted. Your web application runs in a web browser, so you are limited by what a web browser can print.

Web browsers generally do a good job of printing HTML, so in order to generate something to print, you want to first render it as HTML (either to a string or a file) and use an HTML Viewer control to display the HTML. Once you have what you want displayed in an HTML Viewer, you can have a button that calls the Print method of the HTML Viewer to ask the browser to print its contents:

HTMLViewer1.Print

Example Projects

These example projects demonstrate printing:

  • Examples/Printing and Reporting/Printing/GraphicsPrintingExample
  • Examples/Printing and Reporting/Printing/Labels
  • Examples/Printing and Reporting/Printing/Printing To Screen or Printer
  • Examples/Printing and Reporting/Printing/PrintingGraphics
  • Examples/Printing and Reporting/Printing/PrintingText
  • Examples/Printing and Reporting/StyledTextPrinterExample
  • Examples/Web/Printing/HTMLViewerPrinting

See Also

Graphics, PrinterSetup classes; UserGuide:Framework, UserGuide:Pictures, Images and Graphics topics