< Day Day Up > |
TechniquePrinting a document requires the use of a helper class that is associated with a print dialog implemented by the .NET Framework. Create a new class derived from the PrintDocument class in the System.Drawing.Printing namespace. In most cases, you just need to override the OnPrintPage method and allow the base class to handle the remaining printing tasks . The OnPrintPage virtual method has a single PrintPageEventArgs parameter containing several properties that allow you to cancel the print job, query for the page and margin boundaries, and perform rendering using the printer's associated Graphics object. The actual act of printing is the same as it is for rendering to the display. Use the methods defined in the Graphics class for rendering using the MarginBounds and PageBounds to stay within the confines of the printed page. The OnPrintPage method is called only once per page, so if you need more pages for rendering, set the HasMorePages property in the PrintPageEventArgs to true to force another PrintPage event. Listing 10.5 is the printing code for the image editor application whose source code accompanies this book. The OnPrintPage method first determines the size of the header that will be printed, which consists of a string followed by a horizontal line. After the header is rendered, a Rectangle is computed so that an image is drawn underneath the header. Furthermore, if the image is too large to fit on a single printed page, its height and width are scaled down, and the resulting rectangle is centered on the page using information from the MarginBounds property. Listing 10.5 Printing Documentspublic class ImagePrintDocument : PrintDocument { private Image document; public ImagePrintDocument( Image doc ) { this.document = doc; } protected override void OnPrintPage(PrintPageEventArgs e) { // calculate information string and update header height int headerHeight = e.MarginBounds.Y; SizeF strSize = e.Graphics.MeasureString( "Visual C# .Net Developer's Cookbook Chapter 10", new Font("Times New Roman", 12), e.MarginBounds.Width); headerHeight += (int) strSize.Height; // draw the header string e.Graphics.DrawString( "Visual C# .Net Developer's Cookbook Chapter 10", new Font("Times New Roman", 12), new SolidBrush(Color.Blue ), new RectangleF(e.MarginBounds.X, e.MarginBounds.Y, strSize.Width, strSize.Height)); // draw a line under the string e.Graphics.DrawLine( new Pen( new SolidBrush(Color.Black)), e.MarginBounds.X, headerHeight+5, e.MarginBounds.Width+e.MarginBounds.X, headerHeight+5 ); headerHeight += 10; // computer rectangle for image so it's centered on // page and scaled down if too large Rectangle rcImage = new Rectangle(0,0,0,0); if( document.Width >= e.MarginBounds.Width ) { rcImage.X = e.MarginBounds.X; rcImage.Width = e.MarginBounds.Width; } else { // image width is smaller than printed page so center it rcImage.X = (int)((e.MarginBounds.Width/2)-(document.Width/2) + e.MarginBounds.X); rcImage.Width = document.Width; } if( document.Height >= e.MarginBounds.Height-headerHeight) { rcImage.Y = (int)(e.MarginBounds.Y + strSize.Height+20); rcImage.Height = (int)(e.MarginBounds.Height)-headerHeight; } else { // image width is smaller than printed page so center it rcImage.Y = (int)((e.MarginBounds.Height/2)-(document.Height/2)); rcImage.Height = document.Height; } // print the image e.Graphics.DrawImage( document, rcImage, 0, 0, document.Width, document.Height, GraphicsUnit.Pixel ); e.HasMorePages = false; } } To start the printing process, create a PrintDialog object and set any necessary properties to control its behavior. Next, create an instance of the PrintDocument class created earlier and assign it to the Document property of the PrintDialog object. Finally, call the ShowDialog method of the PrintDialog object, and if the result is DialogResult.OK , transfer the PrinterSettings property of the PrintDialog object to the PrinterSettings property of the PrintDocument object and call Print from the PrintDocument instance: private void menuPrint_Click(object sender, System.EventArgs e) { if( image == null ) return; PrintDialog dlg = new PrintDialog(); dlg.AllowSelection = false; dlg.AllowSomePages = false; ImagePrintDocument doc = new ImagePrintDocument( image ); dlg.Document = doc; if( dlg.ShowDialog() == DialogResult.OK ) { doc.PrinterSettings = dlg.PrinterSettings; doc.Print(); } } CommentsA printer is similar to a display adapter in that both are rendering devices. Whereas a display adapter renders output to a monitor, a printer renders its output to a page. However, due to their similarities, the rendering code for both can be the same. The differences lie in the fact that printer output can span multiple pages and a page has a defined margin that you cannot render to. The PrintDocument class is the base class for a helper class that you create to print the contents of your application's current document. As mentioned earlier, in most cases you might just need to override the OnPrintPage method, which in the PrintDocument base class is the event handler delegate for the PrintPage event. In the code listing for this recipe, you might notice that the code to render the Image object is considerably longer than the code used to render the Image to the display. This was merely a design choice on our part. Our goal when printing was to scale the image to fit on a single printed page, center the image on the page, and add a header to the top of the document. This design choice therefore led to some basic math to ensure those design choices applied. |
< Day Day Up > |