C# Printing Functions
by Budi Kurniawan06/24/2002
Printing text and graphics is one of the more important tasks in Windows application
programming. With .NET, simple printing, such as sending a string to the printer, is easy;
however, the .NET Framework lacks a ready-to-use class that encapsulates complex
printing tasks. For example, some coding is required if you want to allow the user to set the
printer and the page to print, change the margins, print more than one copy, etc.
This article offers a brief tutorial on printing using the .NET Framework class
library. It starts with printing a simple string and then proceeds with some coding for
page setup and print preview. To provide printing features in your Windows application,
you should be
familiar with the Graphics class in the System.Drawing
namespace. You can find a
discussion of this class in my previous article, "
System.Drawing with C#."
For printing, you use the System.Drawing.Printing namespace. The
main class in this namespace is the PrintDocument class, which
represents an object that sends
output to the printer. The role of this class is so central that you can achieve simple and
complex printing tasks by using this class alone. However, as we shall see, other classes
in this and other namespaces help make coding easier.
To print text or graphics, you call the Print method of the
System.Drawing.Printing.PrintDocument class. One of the events the
Print method
invokes is the PrintPage event.
You need to wire an event handler to the PrintPage event
and write the code to send output to the printer. The event handler will receive an
argument of type System.Drawing.Printing.PrintPageEventArgs,
containing data related to
the PrintPage event. One of the properties in
PrintPageEventArgs
is Graphics, from
which you can obtain a System.Drawing.Graphics object.
This Graphics object represents
a print page. To send a string to the printer, for example, you use the
Graphics class'
DrawString method. Of course, you can also call other methods of the
Graphics class,
such as FillRectangle, DrawEllipse, etc.
To illustrate how printing is done using members of the
System.Drawing.Printing
namespace, I've created a simple form, shown in Example 1.
This is basically
a blank
form without any printing capability. I will gradually add code to this class to add
printing features. The code in Listing 1 is a form class with a menu containing a
single menu item,
fileMenuItem. This item in turn contains three submenu items:
filePageSetupMenuItem, filePrintPreviewMenuItem, and
filePrintMenuItem.
Listing 1: The form template for printing
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace CSharpPrinting
{
public class Form1 : System.Windows.Forms.Form
{
public Form1()
{
MenuItem fileMenuItem = new MenuItem("&File");
MenuItem filePageSetupMenuItem = new MenuItem("Page Set&up...",
new EventHandler(filePageSetupMenuItem_Click));
MenuItem filePrintPreviewMenuItem = new MenuItem("Print Pre&view",
new EventHandler(filePrintPreviewMenuItem_Click));
MenuItem filePrintMenuItem = new MenuItem("&Print...",
new EventHandler(filePrintMenuItem_Click), Shortcut.CtrlP);
fileMenuItem.MenuItems.Add(filePageSetupMenuItem);
fileMenuItem.MenuItems.Add(filePrintPreviewMenuItem);
fileMenuItem.MenuItems.Add(filePrintMenuItem);
this.Menu = new MainMenu();
this.Menu.MenuItems.Add(fileMenuItem);
}
// -------------- event handlers -------------------------------------
private void filePrintMenuItem_Click(Object sender , EventArgs e)
{
}
private void filePrintPreviewMenuItem_Click(Object sender ,
EventArgs e)
{
}
private void filePageSetupMenuItem_Click(Object sender ,
EventArgs e)
{
}
//-------------- end of event handlers ------------------------------
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
Note that each of the three menu items in fileMenuItem is wired
with an event
handler in its declaration. The event handlers for the three menu items are
filePageSetupMenuItem_Click, filePrintPreviewMenuItem_Click, and
filePrintMenuItem_Click, as shown in the following code,
which is part of the class'
constructor.
MenuItem filePageSetupMenuItem = new MenuItem("Page Set&up...",
new EventHandler(filePageSetupMenuItem_Click));
MenuItem filePrintPreviewMenuItem = new MenuItem("Print Pre&view",
new EventHandler(filePrintPreviewMenuItem_Click));
MenuItem filePrintMenuItem = new MenuItem("&Print...",
new EventHandler(filePrintMenuItem_Click), Shortcut.CtrlP);
As you can see from the code in Listing 1, the three event handlers are currently blank.
private void filePrintMenuItem_Click(Object sender , EventArgs e)
{
}
private void filePrintPreviewMenuItem_Click(Object sender , EventArgs e)
{
}
private void filePageSetupMenuItem_Click(Object sender , EventArgs e)
{
}
Now, we're ready to add code to this template to enable printing. Here is what we will do.
- Add a class-level variable called
printDocof typeSystem.Drawing.Printing.PrintDocument:private PrintDocument printDoc = new PrintDocument(); - In the class' constructor, wire the
PrintPageevent ofprintDocwith an event handler we simply callprintDoc_PrintPage:printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage); - Add code to the
filePrintMenuItem_Clickevent handler:private void filePrintMenuItem_Click(Object sender, EventArgs e) { printDoc.Print(); } - Add code to
printDoc_PrintPage:private void printDoc_PrintPage(Object sender , PrintPageEventArgs e) { String textToPrint = ".NET Printing is easy"; Font printFont = new Font("Courier New", 12); e.Graphics.DrawString(textToPrint, printFont, Brushes.Black, 0, 0); }
|
Related Reading C# in a Nutshell |
The resulting form is given in Listing 2.
Listing 2: The form with code that prints.
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace CSharpPrinting
{
public class Form1 : System.Windows.Forms.Form
{
private PrintDocument printDoc = new PrintDocument();
public Form1()
{
MenuItem fileMenuItem = new MenuItem("&File");
MenuItem filePageSetupMenuItem = new MenuItem("Page
Set&up...", new EventHandler(filePageSetupMenuItem_Click));
MenuItem filePrintPreviewMenuItem = new MenuItem("Print
Pre&view", new EventHandler(filePrintPreviewMenuItem_Click));
MenuItem filePrintMenuItem = new MenuItem("&Print...",
new EventHandler(filePrintMenuItem_Click), Shortcut.CtrlP);
fileMenuItem.MenuItems.Add(filePageSetupMenuItem);
fileMenuItem.MenuItems.Add(filePrintPreviewMenuItem);
fileMenuItem.MenuItems.Add(filePrintMenuItem);
this.Menu = new MainMenu();
this.Menu.MenuItems.Add(fileMenuItem);
printDoc.PrintPage += new PrintPageEventHandler(
printDoc_PrintPage);
}
// -------------- event handlers ---------------------------------
private void filePrintMenuItem_Click(Object sender ,
EventArgs e)
{
printDoc.Print();
}
private void filePrintPreviewMenuItem_Click(Object sender ,
EventArgs e)
{
}
private void filePageSetupMenuItem_Click(Object sender ,
EventArgs e)
{
}
private void printDoc_PrintPage(Object sender ,
PrintPageEventArgs e)
{
String textToPrint = ".NET Printing is easy";
Font printFont = new Font("Courier New", 12);
e.Graphics.DrawString(textToPrint, printFont,
Brushes.Black, 0, 0);
}
//-------------- end of event handlers -------------------------------
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
Now, if you run the form and press Ctrl+P (of course, assuming a printer is connected to your computer and the correct driver is installed), the printer will print the string ".NET printing is easy." Isn't it easy?
Using PrintDialog
Usually in a Windows application, you will see the Print dialog box prior to printing. This dialog box gives the user the chance to cancel printing, change the printer properties, select the number of copies, select the pages to print, etc. If you modify the filePrintMenuItem_Click in Listing 2 with the one in Listing 3,
a Print dialog box will be displayed prior to printing. A Print dialog box is represented by the System.Windows.Forms.PrintDialog class.
Listing 3: Using PrintDialog
private void filePrintMenuItem_Click(Object sender , EventArgs e)
{
PrintDialog dlg = new PrintDialog();
dlg.Document = printDoc;
if (dlg.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
The filePrintMenuItem_Click event handler in Listing 3 only
sends output to the printer if the user clicks the Print dialog box's OK button. However, the settings a user changes in the Print dialog box won't take effect until you write the code to take those options into account.
Page Setup
The following section adds the feature to set up the page that is used for printing. For this, you must perform the following steps.
- Construct an instance of the
System.Drawing.Printing.PageSettingsclass (for this example, I add the following to the Declarations part of the form class):private PageSettings pgSettings = new PageSettings(); - Set
pgSettingsto theDefaultPageSettingsproperty ofprintDocbefore printing. Therefore, add the highlighted code to thefilePrintMenuItem_Clickevent handler in your form:private void filePrintMenuItem_Click(Object sender , EventArgs e) { printDoc.DefaultPageSettings = pgSettings; PrintDialog dlg = new PrintDialog(); dlg.Document = printDoc; if (dlg.ShowDialog() == DialogResult.OK) { printDoc.Print(); } } - Allow the user to change the setting of the page. For our example, add the following
code to the
filePageSetupMenuItem_Clickevent handler:private void filePageSetupMenuItem_Click(Object sender , EventArgs e) { PageSetupDialog pageSetupDialog = new PageSetupDialog(); pageSetupDialog.PageSettings = pgSettings; pageSetupDialog.AllowOrientation = true; pageSetupDialog.AllowMargins = true; pageSetupDialog.ShowDialog(); } - Modify the
printDoc_PrintPageevent handler to take into account the top and left margins. Here is the code for our form:private void printDoc_PrintPage(Object sender , PrintPageEventArgs e) { String textToPrint = ".NET Printing is easy"; Font printFont = new Font("Courier New", 12); int leftMargin = e.MarginBounds.Left; int topMargin = e.MarginBounds.Top; e.Graphics.DrawString(textToPrint, printFont, Brushes.Black, leftMargin, topMargin); }
Now you can select Page Setup from the File menu. What it looks like depends on your printer type. The complete code for the form that includes page setup is given in Listing 4.
Listing 4: The form class that allows the user to change the page setup
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace CSharpPrinting
{
public class Form1 : System.Windows.Forms.Form
{
private PrintDocument printDoc = new PrintDocument();
private PageSettings pgSettings = new PageSettings();
public Form1()
{
MenuItem fileMenuItem = new MenuItem("&File");
MenuItem filePageSetupMenuItem = new MenuItem(
"Page Set&up...", new EventHandler(
filePageSetupMenuItem_Click));
MenuItem filePrintPreviewMenuItem = new MenuItem(
"Print Pre&view", new EventHandler(
filePrintPreviewMenuItem_Click));
MenuItem filePrintMenuItem = new MenuItem("&Print...",
new EventHandler(filePrintMenuItem_Click),
Shortcut.CtrlP);
fileMenuItem.MenuItems.Add(filePageSetupMenuItem);
fileMenuItem.MenuItems.Add(filePrintPreviewMenuItem);
fileMenuItem.MenuItems.Add(filePrintMenuItem);
this.Menu = new MainMenu();
this.Menu.MenuItems.Add(fileMenuItem);
printDoc.PrintPage += new PrintPageEventHandler(
printDoc_PrintPage);
}
// -------------- event handlers ----------------------
private void filePrintMenuItem_Click(Object sender ,
EventArgs e)
{
printDoc.DefaultPageSettings = pgSettings;
PrintDialog dlg = new PrintDialog();
dlg.Document = printDoc;
if (dlg.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
private void filePrintPreviewMenuItem_Click(Object sender ,
EventArgs e)
{
}
private void filePageSetupMenuItem_Click(Object sender ,
EventArgs e)
{
PageSetupDialog pageSetupDialog = new PageSetupDialog();
pageSetupDialog.PageSettings = pgSettings;
pageSetupDialog.AllowOrientation = true;
pageSetupDialog.AllowMargins = true;
pageSetupDialog.ShowDialog();
}
private void printDoc_PrintPage(Object sender ,
PrintPageEventArgs e)
{
String textToPrint = ".NET Printing is easy";
Font printFont = new Font("Courier New", 12);
int leftMargin = e.MarginBounds.Left;
int topMargin = e.MarginBounds.Top;
e.Graphics.DrawString(textToPrint, printFont,
Brushes.Black, leftMargin, topMargin);
}
//-------------- end of event handlers ------------------
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
Printer Setting
You can also enable the user to change printer settings by performing the following steps.
- Create an instance of the
System.Drawing.Printing.PrinterSettingsclass. For our form, add the following line of code:private PrinterSettings prtSettings = new PrinterSettings(); - Set
prtSettingsto thePrinterSettingsproperty of thePageSetupDialog:private void filePageSetupMenuItem_Click(Object sender , EventArgs e) { PageSetupDialog pageSetupDialog = new PageSetupDialog(); pageSetupDialog.PageSettings = pgSettings; pageSetupDialog.PrinterSettings = prtSettings; pageSetupDialog.AllowOrientation = true; pageSetupDialog.AllowMargins = true; pageSetupDialog.ShowDialog(); }
Now the Printer button in the Page Setup dialog is enabled. If you click the Printer button, the Printer setting page will be displayed.
Print Preview
In a Windows application, before the user prints, they can normally view a preview of how the printout will like on paper. You can also provide this feature by adding the following code to the filePrintPreviewMenuItem_Click event handler.
private void filePrintPreviewMenuItem_Click(Object sender , EventArgs e)
{
PrintPreviewDialog dlg = new PrintPreviewDialog();
dlg.Document = printDoc;
dlg.ShowDialog();
}
The Print Preview dialog box is represented by the
System.Windows.Forms.PrintPreviewDialog class. You can create an instance of this dialog box by using its no-argument constructor. Then you must assign the PrintDocument
object to print to the Document property of the
PrintPreviewDialog object. When the
ShowDialog method is called, it will invoke the
PrintPage event of the PrintDocument
object. However, the output will not be sent to the printer but to the
PrintPreviewDialog object. The complete code is given in Listing 5.
Listing 5: The complete code with Page Setup and Print Preview
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace CSharpPrinting
{
public class Form1 : System.Windows.Forms.Form
{
private PrintDocument printDoc = new PrintDocument();
private PageSettings pgSettings = new PageSettings();
private PrinterSettings prtSettings = new PrinterSettings();
public Form1()
{
MenuItem fileMenuItem = new MenuItem("&File");
MenuItem filePageSetupMenuItem = new MenuItem("Page Set&up...",
new EventHandler(filePageSetupMenuItem_Click));
MenuItem filePrintPreviewMenuItem = new MenuItem("Print Pre&view",
new EventHandler(filePrintPreviewMenuItem_Click));
MenuItem filePrintMenuItem = new MenuItem("&Print...",
new EventHandler(filePrintMenuItem_Click), Shortcut.CtrlP);
fileMenuItem.MenuItems.Add(filePageSetupMenuItem);
fileMenuItem.MenuItems.Add(filePrintPreviewMenuItem);
fileMenuItem.MenuItems.Add(filePrintMenuItem);
this.Menu = new MainMenu();
this.Menu.MenuItems.Add(fileMenuItem);
printDoc.PrintPage += new PrintPageEventHandler(
printDoc_PrintPage);
}
// -------------- event handlers ------------------------------------
private void filePrintMenuItem_Click(Object sender ,
EventArgs e)
{
printDoc.DefaultPageSettings = pgSettings;
PrintDialog dlg = new PrintDialog();
dlg.Document = printDoc;
if (dlg.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
private void filePrintPreviewMenuItem_Click(Object sender ,
EventArgs e)
{
PrintPreviewDialog dlg = new PrintPreviewDialog();
dlg.Document = printDoc;
dlg.ShowDialog();
}
private void filePageSetupMenuItem_Click(Object sender ,
EventArgs e)
{
PageSetupDialog pageSetupDialog = new PageSetupDialog();
pageSetupDialog.PageSettings = pgSettings;
pageSetupDialog.PrinterSettings = prtSettings;
pageSetupDialog.AllowOrientation = true;
pageSetupDialog.AllowMargins = true;
pageSetupDialog.ShowDialog();
}
private void printDoc_PrintPage(Object sender ,
PrintPageEventArgs e)
{
String textToPrint = ".NET Printing is easy";
Font printFont = new Font("Courier New", 12);
int leftMargin = e.MarginBounds.Left;
int topMargin = e.MarginBounds.Top;
e.Graphics.DrawString(textToPrint, printFont, Brushes.Black,
leftMargin, topMargin);
}
//-------------- end of event handlers -----------------------------
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
Conclusion
As you can see, this article has shown how to provide the printing feature in your Windows application, step-by-step. However, the code for printing is scattered around the other code. It is a good idea to encapsulate the printing feature in a class of its own so that you can have the printing feature without making your code "dirty."
Budi Kurniawan is a senior J2EE architect and author.
Return to .NET DevCenter


