Author: Lou Adler
How can I control margins when printing text that I have loaded into a TRichEdit?
Answer:
Printing from a RichEdit is really rather easy - all you need to do is to call the
Print method:
RichEdit1.Print(const Caption: string);
The Caption parameter shown here specifies the title that appears in the Print
queue. Therefore you would, for example, call something like:
1
2 RichEdit1.Print(MyAppName + ': ' + DocumentTitle);
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:
3 type
4 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.
Now all we need is the code to implement the margins if needed. This example
function accepts parameters to describe the margins required, the type of
measurements to be used for creating margins and the number of copies to be printed.
5
6 function PrintRichText(RTLeftMargin, RTRightMargin, RTTopMargin, RTBottomMargin:
7 Extended;
8 RichTextMeasurement: TRichTextMeasurements; Copies: Integer): Boolean;
9 var
10 PixelsX, PixelsY, LeftSpace, TopSpace: Integer;
11 LeftMargin, RightMargin, TopMargin, BottomMargin: Extended;
12 begin
13 Result := False; // default return value
14 if RichTextMeasurement <> rtmNone then
15 begin
16 // get pixels per inch
17 PixelsX := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
18 PixelsY := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
19
20 // get non-printable margins
21 LeftSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
22 TopSpace := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);
23
24 LeftMargin := RTLeftMargin;
25 RightMargin := RTRightMargin;
26 TopMargin := RTTopMargin;
27 BottomMargin := RTBottomMargin;
28
29 // If the measurement is set in Centimetres, recalculate
30 if RichTextMeasurement = rtmCentimetres then
31 begin
32 LeftMargin := LeftMargin / 2.54;
33 RightMargin := RightMargin / 2.54;
34 TopMargin := TopMargin / 2.54;
35 BottomMargin := BottomMargin / 2.54;
36 end;
37
38 // Set the Margins
39 R.Left := Round(PixelsX * LeftMargin) - LeftSpace;
40 R.Right := Printer.PageWidth - Round(PixelsX * RightMargin) - LeftSpace;
41 R.Top := Round(PixelsY * TopMargin) - TopSpace;
42 R.Bottom := Printer.PageHeight - Round(PixelsY * BottomMargin) - TopSpace;
43 RichEdit1.PageRect := R;
44 Application.ProcessMessages;
45 end;
46
47 // Print the required number of copies
48 while Copies > 0 do
49 begin
50 RichEdit1.Print('MyApp: Copy ' + IntToStr(Copies));
51 Dec(Copies);
52 Application.ProcessMessages;
53 end;
54 Result := True;
55 end;
To call the example code to print one copy with a 1 inch margin all round, you
could do something like this:
56 procedure TForm1.PrintButtonClick(Sender: TObject);
57 begin
58 if PrintRichText(1, 1, 1, 1, rtmInches, 1) then
59 ShowMessage('Printing was successful')
60 else
61 ShowMessage('Printing failed');
62 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:
63 procedure TForm1.PrintButtonClick(Sender: TObject);
64 begin
65 if PrintRichText(0, 0, 0, 0, rtmNone, 1) then
66 ShowMessage('Printing was successful')
67 else
68 ShowMessage('Printing failed');
69 end;
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.
|