type TForm1 = class(TForm)
Memo1: TMemo; Button1:
TButton; procedure Button1Click(Sender: TObject); private { Private declarations } Procedure
PrintHeader( aCanvas:
TCanvas; aPageCount:
Integer;
aTextrect: TRect; Var continue: Boolean ); Procedure PrintFooter(
aCanvas: TCanvas;
aPageCount: Integer;
aTextrect: TRect; Var continue: Boolean ); public { Public declarations } end;
var Form1:
TForm1;
implementation
uses Printers; {$R *.DFM}
Type THeaderFooterProc = Procedure( aCanvas: TCanvas; aPageCount: Integer;
aTextrect: TRect; Var continue: Boolean ) ofObject;
{ Prototype for a callback method that
PrintString will cal
when it is time to print a header or footer on a page. The
parameters that will be passed to the callback are:
aCanvas : the canvas to output on
aPageCount: page number of the current page, counting from 1
aTextRect : output rectangle that should be used. This will be
the area available between non-printable margin and
top or bottom margin, in device units (dots). Output
is not restricted to this area, though.
continue : will be passed in as True. If the callback sets it
to false the print job will be aborted. }
{+-----------------------------------------------------------
| Function PrintStrings |
| Parameters : | lines:
| contains the text to print, already formatted into
| lines of suitable length. No additional wordwrapping
| will be done by this routine and also no text clipping
| on the right margin!
| leftmargin, topmargin, rightmargin, bottommargin:
| define the print area. Unit is inches, the margins are
| measured from the edge of the paper, not the printable
| area, and are positive values! The margin will be adjusted
| if it lies outside the printable area.
| linesPerInch:
| used to calculate the line spacing independent of font
| size.
| aFont:
| font to use for printout, must not be Nil.
| measureonly:
| If true the routine will only count pages and not produce any
| output on the printer. Set this parameter to false to actually
| print the text.
| OnPrintheader:
| can be Nil. Callback that will be called after a new page has
| been started but before any text has been output on that page.
| The callback should be used to print a header and/or a watermark
| on the page.
| OnPrintfooter:
| can be Nil. Callback that will be called after all text for one
| page has been printed, before a new page is started. The callback
| should be used to print a footer on the page.
| Returns:
| number of pages printed. If the job has been aborted the return
| value will be 0.
| Description:
| Uses the Canvas.TextOut function to perform text output in
| the rectangle defined by the margins. The text can span
| multiple pages. | Nomenclature:
| Paper coordinates are relative to the upper left corner of the
| physical page, canvas coordinates (as used by Delphis Printer.Canvas)
| are relative to the upper left corner of the printable area. The
| printorigin variable below holds the origin of the canvas coordinate
| system in paper coordinates. Units for both systems are printer
| dots, the printers device unit, the unit for resolution is dots
| per inch (dpi).
| Error Conditions:
| A valid font is required. Margins that are outside the printable
| area will be corrected, invalid margins will raise an EPrinter
| exception.
| Created: 13.05.99 by P. Below
+------------------------------------------------------------} Function PrintStrings( lines: TStrings;
Const leftmargin,
rightmargin,
topmargin, bottommargin: Single;
Const linesPerInch:
single;
aFont: TFont;
measureonly: Boolean;
OnPrintheader,
OnPrintfooter: THeaderFooterProc ): Integer; Var continuePrint: Boolean;
{ continue/abort flag for callbacks
} pagecount : Integer;
{ number of current page
} textrect : TRect;
{ output area, in canvas
coordinates } headerrect
: TRect;
{ area for header, in
canvas coordinates } footerrect
: TRect;
{ area for footes, in
canvas coordinates } lineheight
: Integer;
{ line spacing in dots } charheight : Integer;
{ font height in dots } textstart : Integer;
{ index of first line to print o
current page, 0-based. }
{ Calculate text output and
header/footer rectangles. } Procedure CalcPrintRects;
Var X_resolution:
Integer; { horizontal printer
resolution, in dpi } Y_resolution:
Integer; { vertical printer
resolution, in dpi } pagerect
: TRect;
{ total page, in paper coordinates
} printorigin : TPoint; { origin of canvas coordinate system i
paper coordinates. }
{ Calculate area between the requested margins, paper-relative
Adjust margins if they fall outside the printable area.
Validate the margins, raise EPrinter exception if no text area
is left. } Procedure
CalcRects; Var max : Integer;
Begin With textrect DoBegin { Figure textrect in paper coordinates } left := Round(
leftmargin * X_resolution ) ;
If left ‹ printorigin.x Then left
:= printorigin.x;
top := Round(
topmargin * Y_resolution ) ;
If top ‹ printorigin.y Then top
:= printorigin.y;
{ Printer.PageWidth and PageHeight return the size of th
printable area, we need to add the printorigin to get the
edge of the printable area in paper coordinates. } right := pagerect.right - Round( rightmargin * X_resolution
);
max
:= Printer.PageWidth + printorigin.X;
If right › max Then right
:= max;
bottom := pagerect.bottom - Round( bottommargin * Y_resolution
);
max
:= Printer.PageHeight + printorigin.Y;
If bottom › max Then bottom
:= max;
{ Validate the margins. } If (left ›= right)
or (top ›= bottom)
Then raise EPrinter.Create(
'PrintString: the supplied margins are too large, there
'+
'is no area to print left on the page.');
End; {
With }
Procedure
DoPage; Var y:
Integer; Begin y:= textrect.top;
While (textStart ‹ lines.count)
and (y ‹= (textrect.bottom - charheight)) DoBegin { Note: use TextRect instead of TextOut to effect clippin
of the line on the right margin. It is a bit slower,
though. The clipping rect would be
Rect( textrect.left, y, textrect.right, y+charheight). } printer.canvas.TextOut( textrect.left, y, lines[textStart] );
Inc( textStart );
Inc( y, lineheight );
End; {
While } End; {
DoPage }
Begin{ PrintPage } DoHeader;
If
ContinuePrint ThenBegin DoPage;
DoFooter; If (textStart ‹ lines.count)
and ContinuePrint ThenBegin Inc( pagecount );
Printer.NewPage;
End; { If
} End;
End; { PrintPage }
procedure
TForm1.PrintFooter(aCanvas: TCanvas; aPageCount: Integer;
aTextrect: TRect; var continue: Boolean);
var S: String; res: Integer; begin with aCanvas dobegin { Draw a gray line one point
wide below the text } res := GetDeviceCaps( handle, LOGPIXELSY );
pen.Style := psSolid; pen.Color := clGray;
pen.Width := Round(
res / 72 );
MoveTo( aTextRect.Left, aTextRect.Top );
LineTo( aTextRect.Right, aTextRect.Top );
{ Print the page number in Arial
8pt, gray, on right side o
footer rect. } S:=
Format('Page %d', [aPageCount]
);
font.name := 'Arial'; font.Size := 8;
font.Color := clGray; TextOut(
aTextRect.Right - TextWidth(S), aTextRect.Top + res div 18,
S
); end; end;
procedure TForm1.PrintHeader(aCanvas: TCanvas; aPageCount: Integer;
aTextrect: TRect; var continue: Boolean);
var res: Integer; begin with aCanvas dobegin { Draw a gray line one point wide 4 points above the text
} res := GetDeviceCaps( handle, LOGPIXELSY ); pen.Style := psSolid;
pen.Color := clGray; pen.Width := Round( res / 72 );
MoveTo( aTextRect.Left, aTextRect.Bottom - res div 18);
LineTo( aTextRect.Right, aTextRect.Bottom - res div 18 ); { Print the company name in Arial 8pt, gray, on left side o
footer rect. } font.name := 'Arial'; font.Size := 8;
font.Color := clGray; TextOut(
aTextRect.Left, aTextRect.Bottom - res div 10 - TextHeight('W'),
'W. W. Shyster & Cie.' ); end; end;