Printing

 

The basic plan for printing is simple.  The following lucid explanation occurs in the online help in the overview of the PrintDocument  class:

 

·       Create an instance of the PrintDocument class.

·       Set the properties that describe how to print.

·       Call the Print method to start the printing process.

·       Handle the PrintPage event, where you specify the output to print.

 

The PrintPage event handler has an argument of type PrintPageEventArgs; that argument has a member of type Graphics.    You use that object to output graphics to the printer just as you use e.Graphics in your Paint handler.

 

Question:  why can’t we just call the same function, taking a Graphics object,  from the Paint handler and from the PrintPage handler.

 

Let’s try some experiments.   Create a new project PrintDemo.   You need to add a variable of type PrintDocument, initialize it, create a handler for the PrintPage event and attach it to your PrintDocument object.   We will see how to do that (a) by hand in source code and (b) by click-and-drag in Visual Studio.

 

First, let’s do it by hand:  Put

 

using System.Drawing.Printing;

 

near the top of the file, so you can access the PrintDocument class easily.  Then declare

 

private PrintDocument m_PrintDocument = new PrintDocument();

 

[Incidentally, it doesn’t matter if you initialize it where it’s declared, or in the form’s constructor.]

 

Write an empty handler:

 

Void PrintDocumentOnPrintPage(object obj, PrintPageEventArgs e)

{ ;

}

 

and attach it to m_printdoc by putting this line in the constructor:

 

m_printdoc.PrintPage += new PrintPageEventHandler(PrintDocumentOnPrintPage);

 

Now, here’s how to let Visual Studio do this for you, if you want.   Go the form design editor and make the Toobox visible;  scroll down to the very bottom of the Toolbox and you will see a component labeled PrintDocument.  Drag one of those to your form.   You’ll see it at the bottom, where you have seen menus before.  You can use its property sheet to set the name and right-click it to add a handler.  Visual Studio has written the same code we wrote above—look in InitializeComponent to see.

 

Now,  we need a way to initiate the print command.   Add a main menu,  put  File on the menu bar with one menu item Print below File,  and add a handler for the Print menu item:

 

private void Print_Click(object sender, System.EventArgs e)

{

  m_PrintDocument.Print();

}

 

Now we’re set to print, except that we have nothing to print.   Try this:

 

private void PrintDocumentOnPrintPage(object sender, PrintPageEventArgs e)

{ Graphics g = e.Graphics;

  Brush b = new SolidBrush(Color.Black);

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

  g.DrawString("Damn the torpedoes", f,b,0,0);

}

 

Where do you think this will print?  At the upper left corner of the paper, or will there be a margin?  How big do you think the print will be?  Will it be in 16-point type, or will it be 16 pixels high?

 

Answers:   It will be in very legible 16 point type even on a high-resolution laser printer.   It will be at the upper left corner of the printable area of the paper.   Many, perhaps most, printers cannot actually cover the entire surface of the paper with ink no matter what.  (Some more modern printers can do so, since people want to do that when they are printing photos.)  

 

Question:  How can this be?  Since the “pixels” on the printer are (in my case) 300 per inch, while on the screen it’s closer to 100 per inch, you would think the print should be about a third the size you would expect for 16-point type.  But it’s not, it’s the right size. 

 

Answer:   By default the Graphics object you get in PrintPageEventArgs  is set up with units that are 0.01 inch,  according to what the printer driver is telling Windows about the printer.   If your screen resolution is 100 pixels per inch, then you will get the same size print on your printer as on your screen.  

 

There are many different screen resolutions in use.   For example, 800 by 600 on a 15-inch monitor would be 71 pixels per inch;  1280 by 1024 on a 19-inch monitor is 89 to 95 pixels per inch (the pixels aren’t exactly square).   The value of 100 pixels per inch, though, is a reasonable approximation. 

 

You will notice that, in our example program, nothing at all appears on the computer screen, since we didn’t even add a Paint event handler yet.  It seems odd to print something we can’t see.   The obvious thing to do about this is to define a method DrawOrPrint that takes a Graphics object as argument, and call this method from both the Paint handler and the PrintPage handler.   Thus:

 

private void PrintDocumentOnPrintPage(object sender, PrintPageEventArgs e)

{ PrintOrDraw(e.Graphics);

}

 

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{ PrintOrDraw(e.Graphics);     

}

 

private void PrintOrDraw(Graphics g)

{ Brush b = new SolidBrush(Color.Black);

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

  g.DrawString("Damn the torpedoes", f,b,0,0);

}

 

Now you have “what you see is what you get” printing, at least in this simple example.   In general though, there are some differences between painting and printing.   Here are some:

 

·       On a black and white printer, you can’t show colors, so if the screen uses colors, you may want to adjust.   

·       Even if the image is monochrome you may want to take the paper color into account:  A graph may look good on the screen with a black background, but you probably want to print it with a white background.

·       If the document doesn’t fit on one page, you have to worry about where to put the page breaks.   You can’t expect this to be done automatically—you don’t want a one-line “orphan” at the bottom of the page or “widow” at the top of the next page.   In the case of MathXpert, for example, where the document is a sequence of mathematical formulas, I want page breaks only between formulas, not in the middle of a formula.

·       If the document doesn’t fit in the window, you will very likely have scroll bars.  (We’ll learn about programming scroll bars later).   Therefore the Paint handler has to know whether there are scroll bars or not, and keep track of which portion of the document has to be displayed, as not all of it will be displayed at any given time.  

·       The Print handler, on the other hand, has to print the whole document; or maybe you want to give the user a choice to print only some pages, in which case after that choice is made, the Print handler needs to print only the specified pages.

 

We will not go further into these difficulties in this lecture.