|
Even in our increasingly digital age, there remains great power in the printed word. And though most of us are not overly fond of the idea, we typically do end up printing reports as part of our applications. .NET facilitates printing with the help of a
PrintDocument component. Along with this we can make use of the various dialog boxes that are commonly used for printing.
We would first get familiar with the PrintDocument component
The PrintDocument Component
.NET supports printing through methods and properties of the PrintDocument component. The
PrintDocument component is available in the Toolbox and when added to a form, it appears in the component tray at the bottom of the Windows Forms Designer. The
PrintDocument component is not visible at runtime.
The PrintDocument class represents the PrintDocument component and falls under the
System.Drawing.Printing namespace. Typically in a printing application we call the
Print( ) method of the PrintDocument class. It also contains properties such as
DefaultPageSettings, which gets or sets page settings that are used as defaults for all pages to be printed,
PrinterSettings, which gets or sets the printer that prints the document. The class contains events like
BeginPrint, EndPrint and PageEvent. BeginPrint is raised when the
Print( ) method is called and before the first page of the document is printed. Here we can do any initializations if needed.
EndPrint event is raised when the last page of the document has been printed. We can do cleaning up jobs here. The
PrintPage event is raised when it's time to print the current page. We can write code in the handler of this event to do the desired printing. Hence the order of events raised when
Print( ) method is called is BeginPrint, PrintPage and then
EndPrint.
In this article we would use the PrintDocument components and its events to print the contents of a file. For this, we have created a
WinForm application named TextPrint and created a simple GUI as shown in the following figure.
We have added a textbox called filename to the form and a 'Print' button named print. We have also added the
PrintDocument component to our form and renamed it to mypdoc.
Add the Click event handler for the 'Print' button. Add the code in it as shown below:
private void print_Click ( object sender, System.EventArgs e )
{
mypdoc.Print( ) ;
}
In this handler we have simply called the
Print( ) method of the PrintDocument class. Whenever the Print( ) method is called the events are raised. We have not added handlers for the
BeginPrint and EndPrint handlers. We have added a handler only for the
PrintPage event. If we double click on mypdoc in the component tray of the Windows Form Designer, the
mypdoc_PrintPage( ) event handler gets added automatically to the code. This handler is shown below:
private void mypdoc_PrintPage ( object sender, System.Drawing.Printing.PrintPageEventArgs e )
{
StreamReader reader = new StreamReader ( filename.Text ) ;
string str = reader.ReadToEnd( ) ;
reader.Close( ) ;
Font f = new Font ( "Arial", 10 ) ;
e.Graphics.DrawString ( str, f, Brushes.Black, 10, 10 ) ;
}
PrintPageEventsArgs provides data for the
PrintPage event. This data include the Graphics for the printer, the
PageSettings for that page, the bounds of the page, and the size of the margins. We have used the
Graphics object for printing the text.
Here we have created an object referred to by reader of the StreamReader class by passing the file specified in the filename textbox to the constructor of the
StreamReader class. To create an object of the StreamReader class we must add using
System.IO to our code. Then using this object we have called the ReadToEnd( ) method which reads the stream till the end and returns a string which we collected in
str. Next we have created a font object. Then using the DrawString( ) method we printed the string.
Printing Graphics From A File
Now let us see how to print graphics from a file. To demonstrate this we have created a
WinForm application called GraphicsPrint. The UI of this application is same as
TextPrint and the print_Click( ) handler is also same. We have made changes only in the
mypdoc_PrintPage( ) shown below:
private void mypdoc_PrintPage ( object sender,
System.Drawing.Printing.PrintPageEventArgs e )
{
e.Graphics.DrawImage ( Image.FromFile ( filename.Text ), 0, 0 ) ;
}
Here we have passed the file name supplied in the textbox to the
FromFile( ) method of the Image class. We have then passed the Image object returned by the
FromFile( ) method to the DrawImage( ) method. On doing so the contents of the specified file gets printed.
Printing A Multi-page Document
The application that we saw in the previous section which prints text suffer from two limitations-it does not print words of a line that go beyond the margins and it does not print more than one page. This is because the
PrintDocument class does not allow automatic wrapping of words that go beyond the margin. It also crops up words that don't fit into one page.
In this section we have demonstrated how to print a line that goes beyond one line and how to print a multi-page document. To do so we have created a Windows Form Application called
Multipage. As usual, we have added a PrintDocument component and named it
mypdoc. The UI of the application is shown in the following figure.
In addition to the filename text box and the
print button here we have added a multi-line textbox named mytext and a button named
open. The idea is that whichever file is displayed in the mytext textbox gets printed even if the words go beyond the margin and pages are more than one. In the
open_Click( ) event handler we have used an object of the StreamReader class to read from the specified file. Whatever the
StreamReader reads is displayed in the mytext textbox. The handler is shown below:
private void open_Click ( object sender, System.EventArgs e )
{
StreamReader reader = new StreamReader ( filename.Text ) ;
mytext.Text = reader.ReadToEnd( ) ;
reader.Close( ) ;
}
Add the Click event handler for the 'Print' button and add the code in it as shown below:
private void print_Click ( object sender, System.EventArgs e )
{
str = mytext.Text ;
mypdoc.Print( ) ;
}
Here before calling the Print( ) method we have stored the entire text from the text box into a
String called str that we have added as a data member of the form. Here we intend to print multiple pages. Hence we have created the
Font, SolidBrush and StringFormat objects in the handler for the
BeginPrint event. Note that we could have done this in the handler of the
PrintPage event as well but then these objects would have been created for each page. The
mypdoc_BeginPrint( ) event handler is shown below:
private void mypdoc_BeginPrint ( object sender,
System.Drawing.Printing.PrintEventArgs e )
{
f = new Font ( "Arial", 12, FontStyle.Regular ) ;
b = new SolidBrush ( Color.Black ) ;
strformat.Trimming = StringTrimming.Word ;
}
We have added references f (Font),
b (SolidBrush) and strformat (StringFormat) as data members of the form class. Instantiate
strformat in place as
StringFormat strformat = new StringFormat( ) ;
We have set the Trimming property of the
StringFormat class to StringTrimming.Word, which ensures word wrapping.
StringTrimming is an enumeration that specifies how to trim characters from a string that does not completely fit into the specified page layout. Word specifies that text should be trimmed to the nearest word. Next
PrintPage event is raised which invokes the following handler:
private void mypdoc_PrintPage ( object sender, System.Drawing.Printing.PrintPageEventArgs e )
{
RectangleF myrect = new RectangleF ( e.MarginBounds.Left,
e.MarginBounds.Top, e.MarginBounds.Width,
e.MarginBounds.Height ) ;
SizeF sz = new SizeF ( e.MarginBounds.Width, e.MarginBounds.Height);
e.Graphics.MeasureString ( str, f, sz, strformat, out chars, out lines ) ;
printstr = str.Substring ( 0, chars ) ;
e.Graphics.DrawString ( printstr, f, b, myrect, strformat ) ;
if ( str.Length > chars )
{
str = str.Substring ( chars ) ;
e.HasMorePages = true ;
}
else
e.HasMorePages = false ;
}
Here we have created two objects of the RectangleF and
SizeF classes according to the MarginBounds property of the
PaintEventArgs class. This property returns an object of the Rectangle class that represents the portion of the page between the margins. Then we have passed the
Top, Left, Width and Height properties of this rectangle to the constructor of the
RectangleF and SizeF structure.
Next we have called the MeasureString( ) method of the Graphics class which actually does the job of making multi-page printing easy. The first four parameters passed to this method are passed by value and the last two parameters are passed by reference. The first parameter we have passed is the string to be measured (str). Then we have passed f, the
SizeF object that we created and strformat that determines the formatting. The next parameters that we have passed are two integers called
chars and lines that we added as data members of the form. This method measures the string and stores the number of characters in the string in
chars and number of lines in the string in lines that would fit in the current page according to the specified font, format, and size.
Then using the Substring( ) method we retrieved a string that would fit in one page in another string called
printstr that we added as a data member of the form. Next we printed
printstr using the DrawString( ) method. After printing the string we have checked whether the length of the string printed is greater than the number of characters that can fit in one page. If yes, it means that there are more pages to be printed. So, we have collected the remaining string and set the
HasMorePages property of the PrintPageEventArgs to true. This raises the
PrintPage event again and the remaining string also gets measured using the
MeasureString( ) method and then printed using the DrawString( ) method. If this string exceeds one page then again the cycle is repeated. This keeps on happening till the length of string becomes such that it can fit in one page, i.e. the length becomes less than chars.
|