|
A tryst with the printer
The C# Column - Yashawant Kanetkar
Even
in an increasingly digital age, there remains great power in the printed word.
And though most of us are not overly fond of the idea, we 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 will 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 perform any initialisations if needed. The 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 undertake the
desired printing. Hence the order of events raised when Print( ) method
is called is BeginPrint, PrintPage and then EndPrint.
In this article we will 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 filename 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 suffers 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.
This section will demonstrate 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 Figure below:

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, the 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.
 |
Yashavant Kanetkar, one of the first Express Computer
columnists, is an established software expert, speaker and author with several
best-sellers to his credit, including titles like “Let Us C” and the “Fundas”
series. Contact him at kanet@nagpur.dot.net.in |
|