Print Preview Demo

[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]




Search WWW


As of October, 2016, Embarcadero is offering a free release of Delphi (Delphi 10.1 Berlin Starter Edition ).     There are a few restrictions, but it is a welcome step toward making more programmers aware of the joys of Delphi.  They do say "Offer may be withdrawn at any time", so don't delay if you want to check it out.  Please use the feedback link to let me know if the link stops working.


Support DFF - Shop

 If you shop at Amazon anyway,  consider using this link. 


We receive a few cents from each purchase.  Thanks


Support DFF - Donate

 If you benefit from the website,  in terms of knowledge, entertainment value, or something otherwise useful, consider making a donation via PayPal  to help defray the costs.  (No PayPal account necessary to donate via credit card.)  Transaction is secure.

Mensa Daily Puzzlers

For over 15 years Mensa Page-A-Day calendars have provided several puzzles a year for my programming pleasure.  Coding "solvers" is most fun, but many programs also allow user solving, convenient for "fill in the blanks" type.  Below are Amazon  links to the two most recent years.

Mensa 365 Puzzlers  Calendar 2017

Mensa 365 Puzzlers Calendar 2018

(Hint: If you can wait, current year calendars are usually on sale in January.)


Feedback:  Send an e-mail with your comments about this program (or anything else).

Search only





Here's a   "Print Preview" unit which will let you preview and print memo and stringlist data.   As usual, the motivation was the requirement to  preview and print these two component types in another program (the Crossword generator). 

The unit is based  on one among several found at programmer's  It was simple enough to get a handle on and flexible enough to let me add the missing StringGrid preview function.  The author is nearly anonymous  (no name just an invalid email address,  So Ryan, if you ever run across this, drop me a line and I'll be glad to give you a better credit write-up.      

The unit handles multiple pages, scaling of the preview, and the ability to save preview pages and reload them at a later date.  There is much you can learn about metafiles and how they work by studying the code, but not too much that you must learn in order to to use it.      


The unit uses metafiles, one per page, as the ideal mechanism for accurate scaling of the same data to different devices.  A little about metafiles from Microsoft: 

"Enhanced metafiles provide true device independence. You can think of the picture stored in an enhanced metafile as a "snapshot" of the video display taken at a particular moment. This "snapshot" maintains its dimensions no matter where it appears on a printer, a plotter, the desktop, or in the client area of any application.

You can use enhanced metafiles to store a picture created by using the GDI functions (including new path and transformation functions). Because the enhanced metafile format is standardized, pictures that are stored in this format can be copied from one application to another; and, because the pictures are truly device independent, they are guaranteed to maintain their shape and proportion on any output device."

When a metafile is being built, data is written to a special "device context", a structure that defines the characteristics of a particular device.  Borland defines a TCanvas object type to represent a device context and a descendant TMetafileCanvas type to describe the special device context associated with metafiles.   Data is written to either type using the same TCanvas methods.  More significantly,  when a TMetafileCanvas is freed, the data written to it  is encoded in the associated metafile.  The metafile can then it can be saved and/or "played-back" to any specific device type using the "Stretchdraw" command for that device's canvas.  

Print Preview Methods

The main methods from the  PrintPreview unit are:

bulletXInch and YInch convert a passed inch value to pixels using the current metafile resolution. 
bulletMemoOut copies memo text (or any TStringlist object) to the metafile.  Parameters are
bullet aRect : the rectangle describing the area available for the drawing the text.
bulletmemolines: a stringlist containing the text lines to be displayed.
bulletmemofont: the font to be used for displaying the text.
bulletLastCharDisplayed:  If the data cannot all be displayed in the rectangle provided, this is the position of the last character that was displayed.
bulletReturnremainder: A Boolean value indicating whether the input stringlist should have the displayed characters removed.  If true and the list is not empty, the text remaining needs to be displayed in the next column, page, etc. 
bulletStringGridOut write a StringGrid to the MetafileCanvas.  The procedure will check if an OnDrawCell exit is defined for the StringGrid.  If so, a special protocol is used to call the exit.  In a normal DrawCell exit, the passed StringGrid address is used both to provide access to the data and canvas for drawing. In this case the two required address are different  - the grid for data information and the MetafileCanvas for the drawing location.  I solve this be passing the two addresses in a TList to the OnDrawCell exit.  The exit can recognize this case and handle it appropriately.   You can check the demo program for details. 

bulletGrid : The Stringgrid to draw
bullet NewWidth The width of the image on the MetafileCanvas.
bulletOrigin:  The X, Y coordinates of the top left corner of the grid.
bulletShowgrid a Boolean value indicating that the interior gridlines of the Stringgrid are to be drawn  
bulletShowdata A Boolean value indicating that the data in the Stringgrid cells is to be drawn.
bulletNewHeight  An output of StringGridOut indicating the height of the drawn Stringgrid.

bulletGetGridHeight  This function returns the height of the passed StringGrid before it is drawn.  This allows us to move to a new page if necessary before actually rendering the grid.  

Parameters are:
bulletGrid : The Stringgrid to draw
bullet NewWidth The width of the image on the MetafileCanvas.

bulletNewJob: Starts a  new job.
bulletNewPage Start a new page.
bulletPageCount  Number of pages created for this job so far.
bulletCurrentpage The page currently being built or displayed.
bullet PageSize The total width and height of a page 
bullet PrintSize : The height and width of the printable area of the page.
bulletDisplayPage(Page : Integer);
bulletPreview: Setup and display page 1.  
bulletPageNum : The page number to print.
bulletPrintAll: Print all pages.
bulletSaveToFile:  Save the metafiles (one per page) to a single disk file.
bullet  FileName: The file name to save to. 
bullet Note that even though files are EMF format internally, the disk file created is not in standard EMF file format.   There is one file for each preview page but  I write a file stream saving all of the pages (metafiles) in a single disk file. 
bulletLoadFromFile: Load previously saved metafiles.   
bulletFilename : The file name to load from.

The Demo Program

The string grid in the demo  illustrates use of an OnDrawCell exit to display any cell with a valid numeric value in red and underlined. (The grid is initially filled with random numbers and letters. You can double click on any white cell to modify the data.)

On page 1 of the output, the demo will preview or print the StringGrid followed by the introduction memo.  Page 2 has the order reversed and prints the memo in narrow format to force some page breaks.  It will probably result in 4 pages for most devices.

Addendum June 10, 2007:  Version 2 posted today adds the ability to automatically insert a page break when it reaches the end of a page.    Fixed rows (column headers) are replicated at the top of each continues page.   The fixed cells are now colored using the grid's FixedColor property.  

I'll leave the download zip file link for the executable file in the links below because I put it there in 2004.  But there's not much reason to download that I can think of.   

Addendum January 23, 2008:  A recent question from a viewer about right aligned text triggered a restudy of the Margin setting code added last year.  A new button in the demo program prints a message in each corner of the page based on margin values set.    New procedures SetInchMargin and SetPixelMargin make it easy to set margins for each border.   Note for programmers - this change has replaced TSpinEdit controls with TDFFSpinEdit controls in the demo program in order to  achieve compatibility with Turbo Delphi Explorer, a free updated Delphi version which does not include TSpinEdit.

Addendum June 12, 2011:  Another visit to the issue of setting margins.   Version 2.3 changes the margin spin edit display text color to red if the margins extend into the non-printable area of the currently selected printer.    It probably took longer than it should have to realize that there are some inconsistencies in how printer page size characteristics are reported.  There are two ways to determine device characteristics for a printer:

bulletEscape sequences return information for a printer like GETPHYSPAGESIZE (the physical page size in pixels) and  GETPRINTINGOFFSET (the minimum distance from the left and top edges of the paper where printing can start). 
bulletGetDeviceCaps API works for many display device types and returns  HORZRES (maximum horizontal printable size in pixels) and VERTRES (maximum vertical printable size in pixels).  It can also return values for PHYSICALOFFSETX and PHYSICALOFFSETY.

It seems that  modern printer drivers adjust for the non-printable area and reference their drawing from the physical offset coordinates rather than the top left corner of the paper.  Screen drawing does not have this constraint, and it took me several days to realize that.  The implication is that drawing from the MetaCanvasses, which should be device independent, are not quite so.  I finally conceded that fact and adjust  margins on the canvas to allow for non-printable offsets.  Drawing the preview image on the screen subtracts the offsets back out for the on-screen displays.  That appears to be working so I decided to  quit while I'm ahead (for now).     

Download and Explore Programs

Click to download source code for Print Preview and the demo program. 

Click to download executable demo program.

Future Explorations

bulletThe unit  calls the Printer.BeginDoc procedure while building each new page - this is somewhat awkward and would be unnecessary except that  some printer characteristics are used even in scaling the  screen preview.   I think that printer characteristics could be collected at NewJob time and  "BeginDoc"s not issued until actual playback to the printer is taking place. 
bulletI'm suspicious of the methods used to get and set font, pen, and  brush in the metafiles.  They are simply "set" with the equals operator.  I think that assigning the controls would be the proper way to do it.     

  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright 2000-2018, Gary Darby    All rights reserved.