|Controlling Margins when printing RichEdit contents|
How can I control margins when printing text that I have loaded into a TRichEdit?
Printing from a RichEdit is really rather easy - all you need to do is to call the Print method:
RichEdit1.Print(const Caption: string);
From this call the system will carefully format and print the contents of the RichEdit automatically over the required number of pages. That is all well and good, but it does have an unwanted side effect - there is no control over the margins whatsoever. It will simply use the default margins as reported by the Printer when it returns its printable page size.
In order to be able to define the margins you need to know a number of things... The available space on the page, the unprintable area of the page, whether to calculate the margins as Inches or Centimetres, and so on. Much of this can be retrieved from the Printer object, and the rest we will need to provide in our code.
The first thing to decide is how to determine the measurements. You could pass this as a String (e.g. 'inches' or 'centimetres'), you could pass it as a number (e.g. 1 for inches, 2 for centimetres) but perhaps the easiest way is to declare your own data type that will make the code easier to read. For this example I have defined TRichTextMeasurements in the Interface section of the unit:
type TRichTextMeasurements = (rtmNone, rtmInches, rtmCentimetres);
Now we can determine whether to use the default margins (rtmNone) or to create our own
margins in the selected measurement.
function PrintRichText(RTLeftMargin, RTRightMargin, RTTopMargin, RTBottomMargin: Extended; RichTextMeasurement: TRichTextMeasurements; Copies: Integer): Boolean; var PixelsX, PixelsY, LeftSpace, TopSpace: Integer; LeftMargin, RightMargin, TopMargin, BottomMargin: Extended; begin Result := False; // default return value if RichTextMeasurement <> rtmNone then begin // get pixels per inch PixelsX := GetDeviceCaps(Printer.Handle, LOGPIXELSX); PixelsY := GetDeviceCaps(Printer.Handle, LOGPIXELSY); // get non-printable margins LeftSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX); TopSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY); LeftMargin := RTLeftMargin; RightMargin := RTRightMargin; TopMargin := RTTopMargin; BottomMargin := RTBottomMargin; // If the measurement is set in Centimetres, recalculate if RichTextMeasurement = rtmCentimetres then begin LeftMargin := LeftMargin / 2.54; RightMargin := RightMargin / 2.54; TopMargin := TopMargin / 2.54; BottomMargin := BottomMargin / 2.54; end; // Set the Margins R.Left := Round(PixelsX * LeftMargin) - LeftSpace; R.Right := Printer.PageWidth - Round(PixelsX * RightMargin) - LeftSpace; R.Top := Round(PixelsY * TopMargin) - TopSpace; R.Bottom := Printer.PageHeight - Round(PixelsY * BottomMargin) - TopSpace; RichEdit1.PageRect := R; Application.ProcessMessages; end; // Print the required number of copies while Copies > 0 do begin RichEdit1.Print('MyApp: Copy '+IntToStr(Copies)); Dec(Copies); Application.ProcessMessages; end; Result := True; end;
To call the example code to print one copy with a 1 inch margin all round, you could do something like this:
procedure TForm1.PrintButtonClick(Sender: TObject); begin if PrintRichText(1, 1, 1, 1, rtmInches, 1) then ShowMessage('Printing was successful') else ShowMessage('Printing failed'); end;
Note that if you want to use the default margins you still have to pass a number for each margin in the function call. What that number is does not matter as they are all ignored, but perhaps for clarity using a zero would be best:
procedure TForm1.PrintButtonClick(Sender: TObject);
This example can easily be extended to provide visual print progress feedback, or to add margin measurements in millimetres. However, it will not replace a full implementation as provided by commercial Word Processing products. On the other hand, for many purposes it will more than suffice.
© Chris Bray / Vertical Software 2002
|Copyright © The Delphi Corner 2001 All Rights Reserved|