Web solution, Websites help, Java help, C & C# Language help

Tuesday, December 25, 2007

C Language Help, C Language Tutorials, C Language Programming, C Language Tricks { The C# Language }

C Language Help, C Language Tutorials, C Language Programming, C Language Tricks
Printing



One facility that every programmer in the world would want to provide through
his program is that of printing. The .NET world has bestowed about ten important
printer classes that ease our job of printing text and graphics to the printer.
We shall grapple with some small programs to grasp the concepts of printing and
conclude this chapter with a small word processor program that is provided along
with the .NET samples. You should create a text file named a.txt in the current
subdirectory, and thereafter, insert the following three lines:



a.txt

hi, how are you

bye, take care

end



a.cs

using System;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz {

Font f;

StreamReader sr;

public void abc()

{

sr = new StreamReader ("a.txt");

f= new Font("Courier New", 14);

PrintDocument pd = new PrintDocument();

pd.PrintPage += new PrintPageEventHandler(pqr);

pd.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

float lpp = e.MarginBounds.Height / f.GetHeight(e.Graphics) ;

int c = 0 ;

String s=null;

while (c < lpp && ((s=sr.ReadLine()) != null))

{

float y = e.MarginBounds.Top + (c * f.GetHeight(e.Graphics));

e.Graphics.DrawString (s, f, Brushes.Black, e.MarginBounds.Left, y);

c++;

}

if (s != null)

e.HasMorePages = true ;

else

e.HasMorePages = false ;

}

public static void Main() {

zzz a = new zzz();

a.abc();

}

}



The above program prints the contents of the text file a.txt to the default
printer. In all our programs in this chapter, we shall create an object that is
an instance of class zzz and call function abc off it. The code within this
function will execute the actual task of printing.



We first create an object, sr, which is an instance of the class StreamReader.
The constructor of this class is furnished with the name of the file that we
want to print, i.e. a.txt.



The StreamReader class is derived from the class TextReader, which reads
characters from a stream of bytes that have been encoded in a particular format.
The TextReader class belongs to the System.IO namespace. The Stream class too
forms a part of the same genre. This class is designed for reading byte streams.




The StreamReader class is optimised for reading lines of data from an ASCII or a
text file. By default, the encoding used is UTF-8, but it can be changed to any
other encoding format, if required. The UTF-8 encoding can comprehend Unicode
characters. The StreamReader class, by default, is not thread safe, and neither
does it belong to the Printing classes in the .NET family. The class is used in
this program to read the file, one line at a time.



We want the printer to print our text file in a specific font. So, we create a
Font object f, whose constructor is passed the Font Name 'Courier New' along
with the size of '14 points'. We have plenty of choice of fonts from the
innumerable fonts available. For the neophytes of the publishing world, it would
be a revelation that 72 points makes an inch. If we specify a font name such as
'Vijay Mukhi', which does not exist, the printer uses the default font instead,
which in this case, is Microsoft Sans Serif. Thus, the printer always receives a
valid font type to work with.



We create one more object called pd, in our program, which is an instance of
class PrintDocument. This class is the nucleus of all printing activities in the
.NET world. It has an event called PrintPage, which requires an instance of a
delegate PrintPageEventHandler. The delegate represents a method called pqr,
which handles the PrintPage event. This event is generated by the Print
function.



Thus, when we call the Print function, it in turn, calls the pqr function. This
function is passed two parameters. The second parameter is a PrintPageEventArgs
class, which carries data that is useful for printing. The PrintPageEventArgs
class is derived from class EventArgs. The pqr function is not called
explicitly, since this would entail creation of an object like
PrintPageEventArgs.



The Print function is a blocking function. This implies that not a single line
of code will be executed after the Print function has been called, until the pqr
function completes execution. If the pqr function goes into an indefinite loop,
the code succeeding the Print function will never get executed.

As mentioned earlier, the second parameter e of data type PrintPageEventArgs
contains the data that is to be printed. The member MarginBounds, which is of
data type Rectangle, specifies the rectangular portion of the page, which falls
within the margins. In our case, the various values of the Rectangle structure
are as follows:

Height = 900, Width = 650, Left = 100, Right = 750

Top = 100, Bottom = 1000, X = 100, Y = 100.



Before we initiate printing, we need to identify the number of lines that can be
printed on a single page. To estimate this, we use the following calculation:

• Height of our page in pixels divided by the height of the font in pixels.



In this example, it works out to 900 / 22.02691 = 40.85. This value is stored in
the variable lpp, which signifies 'lines per page'.



We then use another variable c, which has an initial value of zero. It is
incremented in the while loop, once for every line that is printed. As soon as
the value of c exceeds that of lpp, the program quits out of the 'while' loop.




The ReadLine function of the StreamReader class fetches a new line from the file
a.txt and stores it within a string variable s. If there are no more lines to be
read from the file, this function returns a null. Thus, the while loop
terminates when the number of lines printed exceed the total number of lines
that can fit on a page or when there are no more lines to be read from the file.




A check must be performed to verify whether we have printed the maximum possible
lines that can fit on a page, before we read the next line from the file. This
is to forestall reading a line from the file and thereafter, realizing that it
cannot be printed on the page due to lack of space. To perform this check, we
determine the y position of each line on the page. All text is printed below the
Top margin. So to calculate the y position of a line, we use the following
calculation:

(Height of the font used MULTIPLIED BY the number of lines printed so far) PLUS
value of the Top margin.

In this case,

The value of the top margin is 100

The height of the font is 22.02691



In the case of the first line to be printed, the number of lines printed so far
is 0.



So, the value of the y co-ordinate for the first line is

=100+(22.02691 X 0) = 100.



The value of the y co-ordinate for the second line is

=100+(22.02691 X 1) = 122.0269.



The value of the y co-ordinate for the third line is

=100+(22.02691 X 2) = 144.0538.



We accessed these values using the WriteLine function.



The Graphics member in class PrintPageEventArgs is employed to write to the
printer. This member contains the function DrawString. This function, which we
had used earlier to write to the screen, is now utilized to write to the
printer.



The DrawString function accepts 5 parameters:

1) A string, s

2) A font, f

3) A color or brush, Black

4) The left margin for the x coordinate, MarginBounds.Left

5) The y co-ordinate



As you may have noticed, the same DrawString function is used for printing to
the printer and writing to the screen. Abstraction, therefore, enables us
exploit and reuse concepts that we have learnt earlier.



The while loop ends when any of the following two conditions is satisfied:

• The number of lines printed exceeds the lines per page i.e. when we need to
print on the next page.

• The file has no more lines to print.

To figure out which of the above conditions has ended the 'while' loop, we
verify the value contained in string s. If the value is null, it signifies that
there are no more lines to print.



As soon as we exceed the maximum number of lines that can be printed on a page,
and there are lines remaining to be printed, there has to be a mechanism to
inform the PrintDocument class that the function pqr needs to be called again,
to print the next page. To accomplish this, the HasMorePages member of the
PrintPageEventArgs object e is either set to true or false. If it is set to
true, the function pqr gets called again.



a.cs

using System;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz

{

Font f;

public void abc()

{

f= new Font("Courier New", 14);

PrintDocument pd = new PrintDocument();

pd.PrintPage += new PrintPageEventHandler(pqr);

pd.PrintPage += new PrintPageEventHandler(xyz);

pd.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

e.Graphics.DrawString ("Vijay Mukhi", f, Brushes.Black, 100, 200);

}

void xyz(object o, PrintPageEventArgs e)

{

e.Graphics.DrawString ("Sonal Mukhi", f, Brushes.Black , 200, 300);

}

public static void Main()

{

zzz a = new zzz();

a.abc();

}

}



Through this example, we once again demonstrate the power of events and
delegates. We attach two methods, pqr and xyz, with the printing event. The
first function pqr prints 'Vijay Mukhi' at X=100 and Y=200 and then, the method
xyz prints 'Sonal Mukhi' at X=200 and Y=300. The HasMorePages property is
initialized to false by the program, even though it has the value of false by
default. Both these lines get printed on the same page.



Each time we set HasMorePages to true, the .NET framework sends a 'form feed'
signal to the printer that sets up a new page for printing. The only mechanism
of printing text to a printer is by means of the Graphics object.



If the 'font' and the 'Brushes' parameters are set to null, a run-time exception
is generated. Hence, they must be explicitly specified. Unlike a dot matrix
printer that prints one line at a time, a laser printer first creates an entire
page in memory and then sends it for printing. Thus, in the function pqr, if we
change the Y coordinate from 200 to 400, both lines get printed on the same
page, since the page first gets created in the memory, and then it is sent to
the printer.



The PrintDocument class creates the PrintPageEventArgs object, since that is the
sole mechanism of activating the printer. Then, it calls all the methods
registered through the delegate.



a.cs

using System;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz

{

public void abc()

{

yyy y = new yyy();

y.PrintPage += new PrintPageEventHandler(pqr);

y.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

System.Console.WriteLine("pqr");

e.Graphics.DrawString ("Sonal Mukhi", new Font("Courier New",10), Brushes.Black,
100, 200);

}

public static void Main()

{

zzz a = new zzz();

a.abc();

}

}

public class yyy : PrintDocument

{

Font f;

protected override void OnQueryPageSettings(QueryPageSettingsEventArgs e)

{

base.OnQueryPageSettings(e) ;

System.Console.WriteLine("OnQueryPageSettings");

}

protected override void OnBeginPrint(PrintEventArgs e)

{

base.OnBeginPrint(e) ;

System.Console.WriteLine("OnBeginPrint");

f = new Font("Courier New",14);

}

protected override void OnEndPrint(PrintEventArgs e)

{

base.OnEndPrint(e) ;

System.Console.WriteLine("OnEndPrint");

}

protected override void OnPrintPage(PrintPageEventArgs e)

{

base.OnPrintPage(e) ;

System.Console.WriteLine("OnPrintPage");

e.Graphics.DrawString ("Vijay Mukhi", f, Brushes.Black, 100, 400);

}

}



Output

OnBeginPrint

OnQueryPageSettings

pqr

OnPrintPage

OnEndPrint



In the above example, class yyy is derived from PrintDocument. Thus, all code
embodied in the PrintDocument class is available to yyy. This also implies that
any code in the class can be overridden. The Print method of the PrintDocument
class had earlier called the methods registered with the delegate, whereas now,
it calls a series of methods from the PrintDocument class. In the situation
where we want to call our methods with the same name as in class yyy, the
keyword 'override' has to be used.



The output confirms that the first function to be called is OnBeginPrint. This
function is akin to an initialization function. All code that is to be executed
only once must be placed in this function. It is a sage programming practice to
always call the original function from the base class. Thus, we use the keyword
base to call the original OnBeginPrint from the class PrintDocument.



Superior programming style decrees that, initially, the base functions should be
called. It is not mandatory to do so, since even if this is not done, the class
still behaves in a similar manner. The documentation too is silent on this
issue, but we consider it prudent to do so and advise you also to call the
original function first.



The parameter PrintEventArgs passed to the function has no significant role to
play in this release. The documentation clearly states that this PrintEventArgs
has been designed for use in a future release. Thus, it cannot be put to any
consequential use at present. We create a Font object in this function, since it
is a one-time activity.



The second function that gets called is OnQueryPageSettings, which will be
elucidated in the next example. Following it, function pqr gets called, which
facilitates printing. Then, function OnPrintPage gets called with the same
parameters as that of the function pqr. If we so desire, we can print in the
delegate method. Other than the delegate method being called first, there is no
apparent difference.



Finally, the function OnEndPrint is called, in which, we are presented with the
opportunity to clean up any resources created in the method OnBeginPrint.



a.cs

using System;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz

{

public void abc()

{

yyy y = new yyy();

y.PrintPage += new PrintPageEventHandler(pqr);

y.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

e.Graphics.DrawString ("Sonal Mukhi", new Font("Courier New",10), Brushes.Black,
100, 200);

}

public static void Main()

{

zzz a = new zzz();

a.abc();

}

}

public class yyy : PrintDocument

{

Font f;

protected override void OnQueryPageSettings (QueryPageSettingsEventArgs e)

{

base.OnQueryPageSettings(e) ;

e.PageSettings.Landscape = true;

}

protected override void OnBeginPrint(PrintEventArgs e)

{

base.OnBeginPrint(e) ;

f = new Font("Courier New",14);

}

protected override void OnPrintPage(PrintPageEventArgs e)

{

base.OnPrintPage(e) ;

e.Graphics.DrawString ("Vijay Mukhi", f, Brushes.Black, 100, 400);

}

}



Each time we use the printer, we may be desirous of customizing the print
settings for each page. To enable this, the framework calls the function
OnQueryPageSettings before printing any page. In this function, we can change
the page settings using the parameter e, which is of type
QueryPageSettingsEventArgs. This class is derived from PrintEventArgs class.



One of the members in QueryPageSettingEventArgs is PageSettings, which contains
a large number of properties that control the printer settings. Here, we have
only used the Landscape property and assigned it a boolean value of true. Had we
assigned it a value of false, the property would have been set to Portrait mode,
which is usually the default mode.



Other properties that can be modified are: the paper tray i.e. the source from
where the paper is fed to the printer, the printer resolution, the page margins,
the color etc. Any property of a printer that can be set manually can now be
done using this function.



a.cs

using System;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz

{

public void abc()

{

yyy y = new yyy();

y.PrintPage += new PrintPageEventHandler(pqr);

y.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

e.Graphics.DrawString ("Sonal Mukhi", new Font("Courier New",10), Brushes.Black,
100, 200);

}

public static void Main()

{

zzz a = new zzz();

a.abc();

}

}

public class yyy : PrintDocument

{

Font f;

protected override void OnPrintPage(PrintPageEventArgs e)

{

base.OnPrintPage(e) ;

e.Cancel = true;

f = new Font("Arial",13);

e.Graphics.DrawString ("Vijay Mukhi", f, Brushes.Black, 100, 400);

}

}



In this program, the Cancel property of PrintPageEventArgs is set to true,
resulting in cancellation of the print job. The printing that was to be carried
out by the delegate function also gets cancelled. All print jobs are aborted.
The PageSettings object used in the earlier program is also a property of the
PrintPageEventArgs class, and thus, can be used in this function too.



a.cs

using System;

using System.Windows.Forms;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz

{

public void abc()

{

PrintDocument y = new PrintDocument ();

y.PrintPage += new PrintPageEventHandler(pqr);

PrintDialog d = new PrintDialog() ;

d.Document = y;

DialogResult r = d.ShowDialog();

if (r == DialogResult.OK)

y.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

e.Graphics.DrawString ("Sonal Mukhi", new Font("Courier New",10), Brushes.Black,
100, 200);

}

public static void Main()

{

zzz a = new zzz();

a.abc();

}

}



In this example, we would like to display a dialog box to the user where he can
change the printing options. Therefore, firstly we create an object d as an
instance of class PrintDialog. Creating a PrintDialog object assigns default
values to the following eight properties:



• AllowSomePages is set to False, disabling the Pages option button.

• AllowSelection is set to False, disabling the Selection option button.

• AllowPrintToFile is set to True, enabling Print to File check box.

• Document, which is a reference to the PrintDocument object, is set to null.


• PrinterSettings is assigned the value of False, disabling the dialog box.

• PrintToFile decides whether the printer would print to disk or to the printer.
If the value is null, it prints to the printer.

• ShowHelp is set to False, thus disabling the help button.

• ShowNetwork is set to True, thus enabling the network button.



We can modify any of these values to befit our requirements. We can also select
specific parts of the document to print.



Screen 6.1



When we run the program, the normal Windows Printer Dialog box is displayed,
allowing us to modify any of the properties. The ShowDialog function facilitates
the display of the dialog box. This function waits until one of two the buttons,
OK or Cancel, is clicked.The value returned on clicking one of these two buttons
is stored in the DialogResult object r.



If the OK button is selected, it will start the printing, whereas if the Cancel
button is selected, it will cancel or abort the printing. When the OK button is
selected, the function ShowDialog returns an enum DialogResult, with a value OK.
The above enum can have as many as 8 different values, depending upon the type
of buttons available in the Dialog Box. Thereafter, the Print function of the
PrintDialog class is called.



One of the final actions of the function ShowDialog is to initialize the
Document property supplied by PrintDocument object, i.e. y, to the printer
settings chosen in the Dialog box.



a.cs

using System;

using System.Windows.Forms;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz

{

public void abc()

{

PrintDocument y = new PrintDocument ();

y.PrintPage += new PrintPageEventHandler(pqr);

PageSetupDialog p = new PageSetupDialog () ;

PageSettings s = new PageSettings();

p.PageSettings = s ;

p.ShowDialog ();

y.DefaultPageSettings = s;

y.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

e.Graphics.DrawString ("Sonal Mukhi", new Font("Courier New",10), Brushes.Black,
100, 200);

}

public static void Main()

{

zzz a = new zzz();

a.abc();

}

}



In the above example we usher in a new class, PageSetupDialog, which allows the
user to change page settings such as the margins and the paper orientation. When
we create a PageSetupDialog object, properties in the object get initialized to
their default values.



Some of the properties are :

• AllowMargins: set to true, enables us to change the margins settings.

• AllowOrentation: set to true, enables the Portrait/Landscape radio buttons.

• AllowPaper: set to true, so that we can choose the paper size and source.

• AllowPrinter: set to true, enables the printer button.

• MinMargins: set to null, so that the default margins of 1 inch are displayed.

• PageSettings: set to null.

• PrinterSettings: set to null.



It is mandatory to initialise the PageSettings property to an actual object
containing the settings selected by the user. Finally the function ShowDialog
initializes the object s.



Screen 6.2



Then, the property DefaultPageSettings of the PrintDocument class is initialised
to the PageSettings object s, so that the printing framework uses the settings
stored in this property. Thus, the two dialog boxes have their own unique
purposes, and each of them fills up an object that is used by the PrintDocument
class. In the Windows world, Dialog boxes are used to fill up
properties/variables in an object.



In the above two programs, the function pqr does not receive any values from the
dialog boxes.



a.cs

using System;

using System.Windows.Forms;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz {

public void abc()

{

PrintDocument pd = new PrintDocument();

pd.PrintPage += new PrintPageEventHandler(pqr);

PrintPreviewDialog dlg = new PrintPreviewDialog() ;

dlg.Document = pd;

dlg.ShowDialog();

pd.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

e.Graphics.DrawString ("Sonal Mukhi", new Font("Courier New",10), Brushes.Black,
100, 200);

}

public static void Main() {

zzz a = new zzz();

a.abc();

}

}



Screen 6.3



Before we buy goods, we often like to preview them. The same analogy is true
when we want to print a document. The class PrintPreviewDialog enables us to
preview a document before printing it. The only property that is to be
initialized here is Document property. This is mandatory since there is no other
mechanism by which the Dialog box can receive the contents of the page.



We can safely assume that the ShowDialog function calls Print, which figures out
the text to be printed on a page. It also has the ability to display the content
in different magnification percentages and in multiple pages at a time. The
Dialog contains a PrintPreviewControl, which has several members that can be
toyed around with, in order to transform the appearance.





a.cs

using System;

using System.Windows.Forms;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

public class zzz

{

public void abc()

{

PrintDocument pd = new PrintDocument();

pd.PrintPage += new PrintPageEventHandler(pqr);

pd.Print();

}

void pqr(object o, PrintPageEventArgs e)

{

Image i = Image.FromFile("Sample.jpg");

Point p = new Point(100, 100);

e.Graphics.DrawImage(i, p);

e.Graphics.DrawString ("Sonal Mukhi", new Font("Courier New",10), Brushes.Black,
100, 600);

}

public static void Main()

{

zzz a = new zzz();

a.abc();

}

}



A printer has the capability of not only printing text, but also lines,
ellipses, curves and images. This program prints an image. Before you proceed,
ensure that file sample.jpg resides in the current directory.



The Image class constructor is supplied with a jpg file, which we have picked up
from the .NET samples. The Point object p represents the X, Y coordinates where
the image is to be drawn. Then, using the DrawImage function from the Graphics
class, the image is printed at the position specified. Using this procedure, all
images displayed on the screen in the previous chapters can be sent to the
printer for printing.

No comments: