Printer Settings


So far, all the printing in this chapter has been done to the default printer, as defined by Windows itself. The user can change the printer for a document via the Printer button on the PageSetupDialog. It's more common, however, to allow the user to choose the printer after choosing the Print item from the File menu. For this you use the PrintDialog component, as shown in Figure 7.9.

Figure 7.9. The PrintDialog Component

Using the PrintDialog component looks like this:

 PrintDialog printDialog1; void InitializeComponent() {   ...   this.printDialog1 = new PrintDialog();   ...   // Can set the PrintDialog's Document property   // in the Property Browser   this.printDialog1.Document = this.printDocument1;   ... } void printButton_Click(object sender, System.EventArgs e) {   // Let the user choose the printer   if( printDialog1.ShowDialog() == DialogResult.OK ) {     printDocument1.Print();   } } 

Like PageSetupDialog, the PrintDialog component allows you to set a number of options before it is shown:

 sealed class PrintDialog : CommonDialog, IComponent, IDisposable {   // Constructors   public PrintDialog();   // Properties   public bool AllowPrintToFile { get; set; }   public bool AllowSelection { get; set; }   public bool AllowSomePages { get; set; }   public PrintDocument Document { get; set; }   public PrinterSettings PrinterSettings { get; set; }   public bool PrintToFile { get; set; }   public bool ShowHelp { get; set; }   public bool ShowNetwork { get; set; }   // Events   public event EventHandler HelpRequest;   // Methods   public virtual void Reset(); } 

You must set the Document property before showing a PrintDialog object. The other PrintDialog properties are similar in function to the PageSetupDialog properties. A couple of properties are special, however, because they determine what to print. Let's take a look.

Print Range

The AllowSelection property of the PrintDialog lets the user print only the current selection, [2] and AllowSomePages allows the user to decide on a subset of pages to be printed. Both settings require you to print specially, based on the PrintRange property of the PrinterSettings class, which is of type PrintRange:

[2] What, if anything, the "current selection" means is application-specific. However, Betsy Hardinger, the copy editor for this book, made an impassioned plea during her editing of this book that when the print dialog is invoked while there is a current selection, the print dialog default to printing only the selection and not all 75 pages of the document (which Betsy often finds herself printing when she doesn't want to). Thank you.

 enum PrintRange {   AllPages, // Print all pages (default)   Selection, // Print only the current selection   SomePages, // Print pages from FromPage to ToPage } 

Before you can set a print range that's different from AllPages, you must set AllowSelection or AllowSomePages (or both) to true (they both default to false). AllowSomePages also requires that the PrinterSettings FromPage and ToPage be set greater than the default of zero:

 int totalPages = 13; int page; int maxPage; void printButton_Click(object sender, System.EventArgs e) {   printDocument1.PrinterSettings.FromPage = 1;   printDocument1.PrinterSettings.ToPage = totalPages;   printDocument1.PrinterSettings.MinimumPage = 1;   printDocument1.PrinterSettings.MaximumPage = totalPages;   printDialog1.AllowSomePages = true;   if( printDialog1.ShowDialog() == DialogResult.OK ) {     printDocument1.Print();   } } 

Although it's not required, it's a good idea when setting AllowSomePages to true to also set MinimumPage and MaximumPage so that users can't accidentally ask for a page out of the allowed range. If AllowSelection or AllowSomePages is set to true, the PrintPage event will have to check the PrintRange and FromPage/ToPage properties to see what to print:

 int totalPages = 13; int page; int maxPage; void printButton_Click(object sender, System.EventArgs e) {   ...   if( printDialog1.ShowDialog() == DialogResult.OK ) {  if( printDialog1.PrinterSettings.PrintRange ==   PrintRange.SomePages ) {   // Set first page to print to FromPage   page = printDocument1.PrinterSettings.FromPage;   // Set last page to print to ToPage   maxPage = printDocument1.PrinterSettings.ToPage;   }   else {   // Print all pages   page = 1;   maxPage = totalPages;   }  // Print from first page to last page     printDocument1.Print();   } } void printDocument1_PrintPage(object sender, PrintPageEventArgs e) {   Graphics g = e.Graphics;   // print current page...  // Check whether there are more pages to print   ++page;   e.HasMorePages = (page <= maxPage);  } 

In addition to the PrintRange, FromPage, and ToPage properties, the PrinterSettings class has many more settings for use in determining exactly how the user would like to print:

 class PrinterSettings : ICloneable {   // Constructors   public PrinterSettings();   // Properties   public bool CanDuplex { get; }   public bool Collate { get; set; }   public short Copies { get; set; }   public PageSettings DefaultPageSettings { get; }   public Duplex Duplex { get; set; }  public int FromPage { get; set; }  public static StringCollection InstalledPrinters { get; }   public bool IsDefaultPrinter { get; }   public bool IsPlotter { get; }   public bool IsValid { get; }   public int LandscapeAngle { get; }   public int MaximumCopies { get; }   public int MaximumPage { get; set; }   public int MinimumPage { get; set; }   public PaperSizeCollection PaperSizes { get; }   public PaperSourceCollection PaperSources { get; }   public string PrinterName { get; set; }   public PrinterResolutionCollection PrinterResolutions { get; }  public PrintRange PrintRange { get; set; }  public bool PrintToFile { get; set; }   public bool SupportsColor { get; }  public int ToPage { get; set; }  // Methods   public Graphics CreateMeasurementGraphics(); } 

One thing of particular interest is the CreateMeasurementGraphics method, which returns a Graphics object based on the printer and its settings. You can use this Graphics object for making measurement calculations and for enumerating the font families (using the FontFamily. GetFamilies method), all without having to actually start a print operation.

Targeting the Printer

I'd like to remind you again that because the drawing happens on a Graphics object, all the drawing techniques from Chapters 4, 5, and 6 work just as well with printers as they do with screens. However, unlike the screen, where page units default to Pixel, the page units for the printer default to Display. Furthermore, whereas Display means Pixel on the screen, for the printer, Display maps the printer resolution to a logical 100 dpi. Because printers often have different resolutions both vertically and horizontally and are almost never 100 dpi anyway, this may seem unintuitive. However, because the default system font setting is 96 dpi on the screen, mapping the printer to a logical 100 dpi means that the default mappings for both screen and printer yield a quick and dirty near-WYSIWYG, without your having to change a thing. If you want something even closer, you're free to use page units such as inches or millimeters, as discussed in Chapter 6: Advanced Drawing.

If you do change the units, remember to convert PageBounds and MarginBounds to the new units as well. You can use the Graphics method TransformPoints:

 static RectangleF TranslateBounds(Graphics g, Rectangle bounds) {   // Translate from units of 1/100th of an inch to page units   float dpiX = g.DpiX;   float dpiY = g.DpiY;   PointF[] pts = new PointF[2];   pts[0] =     new PointF(bounds.X * dpiX / 100, bounds.Y * dpiY / 100);   pts[1] =     new PointF(bounds.Width * dpiX / 100, bounds.Height * dpiX / 100);  g.TransformPoints(   CoordinateSpace.Page, CoordinateSpace.Device, pts);  return new RectangleF(     pts[0].X,     pts[0].Y,     pts[1].X,     pts[1].Y); } 

The TranslateBounds helper method uses the current Graphics object to translate a PageBounds or MarginBounds rectangle from units of 100 dpi to whatever the page unit is set to. This helper is meant to be used from the PrintPage handler:

 void printDocument1_PrintPage(object sender, PrintPageEventArgs e) {   Graphics g = e.Graphics;  g.PageUnit = GraphicsUnit.Inch;  using( Pen thinPen = new Pen(Color.Black, 0) ) {     RectangleF pageBounds = GetRealPageBounds(e, preview);     pageBounds =  TranslateBounds(g, Rectangle.Truncate(pageBounds));  g.DrawRectangle(       thinPen,       pageBounds.X,       pageBounds.Y,       pageBounds.Width,       pageBounds.Height);     ...   }   ... } 

Notice that PageUnit is set on the Graphics object right away so that any drawing that takes place in the PrintPage handler will be in those units.

Finally, notice that the PrintPage handler sets the PageUnit during each page being printed. Each time the PrintPage handler is called, it gets a fresh Graphics object, so don't forget to reset its options every time.



Windows Forms Programming in C#
Windows Forms Programming in C#
ISBN: 0321116208
EAN: 2147483647
Year: 2003
Pages: 136
Authors: Chris Sells

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net