2010. június 5., szombat

How to change the font size when printing a TRichEdit


Problem/Question/Abstract:

I am using a TRichEdit in my application that shows text in a 10 point character size. I would like to print it using a size of 13. How can I change the printing size?

Answer:

If the whole contents of the TRichEdit use the same font size the simplest method would be to simply assign 13 to richedit.font.size, print the bugger and revert the size to 10. One could do this with a hidden TRichEdit control that contains a copy of the text, if the user should not be aware of what is going on.

This method will break as soon as the rich edit control contains formatted text in several font sizes. In this case one can scale the printer canvas by using a custom mapping mode. Unfortunately this means one has to do the printing manually, since the mapping mode can only be set after a BeginDoc and richedit.print will then fail. Here is an example that will print a TRichEdit 1.3 times the original size. It assumes all text will fit onto the first page. If several pages need to be printed the scaling of the printer canvas needs to be redone after each NewPage, since that resets the printer canvas to the default mapping mode!


procedure TForm1.Button1Click(Sender: TObject);
var
  r: TRect;
  richedit_outputarea: TRect;
  printresX, printresY: Integer;
  fmtRange: TFormatRange;
begin
  printer.begindoc;
  try
    r := Rect(1000 div 13, 1000 div 13, Round((Printer.PageWidth - 100) / 1.3),
      Round((Printer.Pageheight - 100) / 1.3));
    SetMapMode(printer.canvas.handle, MM_ANISOTROPIC);
    SetWindowExtEx(printer.canvas.handle, GetDeviceCaps(printer.canvas.handle,
      LOGPIXELSX), GetDeviceCaps(printer.canvas.handle, LOGPIXELSY), nil);
    SetViewportExtEx(printer.canvas.handle, Round(GetDeviceCaps(printer.canvas.handle,
      LOGPIXELSX) * 1.3), Round(GetDeviceCaps(printer.canvas.handle,
      LOGPIXELSY) * 1.3), nil);
    with Printer.Canvas do
    begin
      printresX := Round(GetDeviceCaps(handle, LOGPIXELSX) / 1.3);
      printresY := Round(GetDeviceCaps(handle, LOGPIXELSY) / 1.3);
      {Define a rectangle for the rich edit text. The height is set to the maximum.
                  But we need to convert from device units to twips, 1 twip = 1/1440 inch or 1/20
                        point.}
      richedit_outputarea := Rect(r.left * 1440 div printresX, r.top * 1440 div
        printresY, r.right * 1440 div printresX, r.bottom * 1440 div printresY);
      {Tell rich edit to format its text to the printer. First set up data record
                        for message:}
      fmtRange.hDC := Handle; {printer handle}
      fmtRange.hdcTarget := Handle; {ditto}
      fmtRange.rc := richedit_outputarea;
      fmtRange.rcPage := Rect(0, 0, Printer.PageWidth * 14400 div 13 div printresX,
        Printer.PageHeight * 14400 div 13 div printresY);
      fmtRange.chrg.cpMin := 0;
      fmtRange.chrg.cpMax := richedit1.GetTextLen - 1;
      {Format the text}
      richedit1.Perform(EM_FORMATRANGE, 1, Longint(@fmtRange));
      {Free cached information}
      richedit1.Perform(EM_FORMATRANGE, 0, 0);
    end;
  finally
    printer.enddoc;
  end;
end;


The richedit1.perform( EM_FORMATRANGE call returns the index of the last character that could be fitted into the passed fmtrange.rc, + 1. So if multiple pages are required one repeats with fmtrange.chrg.cpMin set to this value, until all characters have been printed. Note that the rich edit control strips blanks and linebreaks off the end of the text so the number of characters to output may be smaller than richedit.gettextLen .

Nincsenek megjegyzések:

Megjegyzés küldése