delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback



Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi








Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (3)


RichEdit Print PreviewFormat this article printer-friendly!Bookmark function is only available for registered users!
Product:
Delphi all versions
Category:
VCL-General
Skill Level:
Scoring:
Last Update:
01/14/2002
Search Keys:
delphi delphi3000 article borland vcl code-snippet RichEdit Control Print Preview tMetafileCanvas EM_FORMATRANGE
Times Scored:
4
Visits:
9550
Uploader: Jochen Fromm
Company:
Reference: N/A
 
Question/Problem/Abstract:
How do you display a correct Print-Preview for a common
Richedit Control ?
Answer:



The task seems simple, but is not so easy as it seems.
Even Microsoft admits, that there are some problems,
as the Microsoft Articles

Q142320 PRB: Rich Edit Control Improperly Displays Print Preview
Q253262 HOWTO: Store the Contents of an RTF Control in an EMF File

show.
To display a correct Print-Preview with correct
Text-Heights and -Widths, you can draw the RichEdit-Control
on a Metafile, and print this Metafile to the Preview-Canvas :

// r : Destination Rectangle (on Preview or Printer Canvas)
// XInch : Width in Inch of rectangle to print
// YInch : Height in Inch of rectangle to print
// xalign,yalign : Alignment in horizontal and vertical direction

tRichEditAlign = (rTop,rBottom,rCentered);

procedure PrintRichEdit(RichEdit    : tMyRichEdit;
                        Canvas      : tCanvas;
                        r           : tRect;
                        XInch,YInch : extended;
                        xalign      : tAlignment;
                        yalign      : tRicheditAlign);
var Meta : tMetafile;
    MetafileRect : tRect;
begin
  RichEdit.SelStart:=0;
  RichEdit.SelLength:=Length(RichEdit.Text);
  RichEdit.Paragraph.Alignment:=xAlign;

  if (XInch < 0) or (YInch < 0) then exit;
  if Canvas <> Printer.Canvas then
  begin
    // Preview with Metafile
    Meta:=tMetafile.Create;
    Meta.MMWidth :=round(XInch*2.54*1000);   // Unit is 0.01 mm
    Meta.MMHeight:=round(YInch*2.54*1000);
    MetafileRect:=Rect(0,0,Meta.MMWidth,Meta.MMHeight);
    with tMetafileCanvas.Create(Meta,0) do
     try
      RichEdit.PrintPreview(Handle,MetafileRect,yAlign);
     finally
      free;
     end;
    Canvas.StretchDraw(r,Meta);
    Meta.Free;
  end else
    // Printing
    RichEdit.PrintRect(Printer.Canvas.Handle,r,yAlign);
end;


To extent the functionality I use here a modified
print procedure, that replaces the original
the TCustomRichEdit.Print method :

tMyRichEdit = class(tRichEdit)
public
  procedure PrintRect(dc : HDC;r : tRect;align : tRichEditAlign);
  procedure PrintPreview(dc : HDC;r : tRect;align : tRichEditAlign);
end;

procedure tMyRichEdit.PrintRect(dc    : HDC;
                                r     : tRect;
                                align : tRichEditAlign);
// see Windows SDK in MSDN :
// in /Platform SDK/User Interface Services/Windows User Interface/...
//          .../Controls/Rich Edit Controls
var
  Range: TFormatRange; // defined in Unit RichEdit.pas
  LogX, LogY, OldMap, h : Integer;
  SaveRect: TRect;
begin
  FillChar(Range, SizeOf(TFormatRange), 0);
  with Printer, Range do
  begin
    hdc := dc;
    hdcTarget := dc;
    LogX := GetDeviceCaps(dc, LOGPIXELSX);
    LogY := GetDeviceCaps(dc, LOGPIXELSY);

    // 1 Twip = 1/20 of a Point, a typographic point is 1/72 Inch
    // (Device-Coordinates / DPI --> Inches) *72 * 20 --> Twips
    rc.left   := round((r.Left / LogX) * 1440);
    rc.top    := round((r.Top / LogY) * 1440);
    rc.right  := round((r.Right / LogX) * 1440);
    rc.bottom := round((r.Bottom / LogY) * 1440);

    rcPage := rc;
    SaveRect := rc;

    // print entire content
    chrg.cpMax := -1;
    // ensure printer DC is in text map mode
    OldMap := SetMapMode(hdc, MM_TEXT);
    // flush buffer
    SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0);
    try
      rc := SaveRect;
      chrg.cpMin := 0;
      // wParam = 0 : get Text-Height
      SendMessage(Self.Handle, EM_FORMATRANGE, 0, Longint(@Range));
      chrg.cpMin := 0;
      h:=rc.bottom-rc.top;
      rc := SaveRect;
      case align of
        rBottom   : rc.top := SaveRect.Bottom-h-5;  // 5 Twips = 0.1 mm
        rCentered : rc.top := SaveRect.top+
                            ((SaveRect.Bottom-SaveRect.top)-h) div 2;
      end;

      // wParam = 1 : print (only text that fits in region range.rc)
      SendMessage(Self.Handle, EM_FORMATRANGE, 1, Longint(@Range));
      // flush buffer
      SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0);
     finally
      SetMapMode(hdc, OldMap);       // restore previous map mode
    end;
  end;
end;

function GetPreciseTextLen(ARichEditCtrl : TRichedit): integer;
var
  gtlex : TGetTextLengthEx;
begin
  with gtlex do
  begin
    flags := GTL_PRECISE;
    codepage := CP_ACP;
  end;
  Result := ARichEditCtrl.Perform(EM_GETTEXTLENGTHEX,WPARAM(@gtlex), 0 );
end;

procedure tMyRichEdit.PrintPreview(dc    : HDC;
                                   r     : tRect;
                                   align : tRichEditAlign);
// Extension of tCustomRichEdit.Print in ComCtrls.pas
var
  Range: TFormatRange; // definiert in Unit RichEdit.pas
  SaveRect: TRect;
  fx,fy : double;
  DisplayDC : HDC;
  dpiX,dpiY,HSize,VSize,HRes,VRes,h,maxlen : integer;
begin
  FillChar(Range, SizeOf(TFormatRange), 0);
  with Printer, Range do
  begin
    hdc := dc;

    // Calculate correction-factors :
    //  fx = GetDeviceCaps(DC,HorzSize)   (Screen-Width in mm)
    //     * GetDeviceCaps(DC,LogPixelsX) (dpi Screen)
    //     / 25.4                         (Factor Inch -> mm)
    //     / GetDeviceCaps(DC,HorzRes)    (Screen-Width in Pixel)
    //
    // you find e.g. fx = 1.18 for Screen.Width = 1024,
    //               fx = 1.5 for Screen.Width = 800

    DisplayDC := CreateDC('DISPLAY',nil,nil,nil);
    HSize:=GetDeviceCaps(DC,HorzSize);
    VSize:=GetDeviceCaps(DC,VertSize);
    dpiX :=GetDeviceCaps(DC,LogPixelsX);
    dpiY :=GetDeviceCaps(DC,LogPixelsY);
    VRes :=GetDeviceCaps(DC,VertRes);
    HRes :=GetDeviceCaps(DC,HorzRes);
    if HRes > 0
     then fx:=HSize*dpiX/25.4/HRes
     else fx:=1.0;
    if VRes > 0
     then fy:=VSize*dpiY/25.4/VRes
     else fy:=1.0;
    hdcTarget:=DisplayDC;

    // convert 0.01 mm to 1 Twip
    rc.left   := round((r.Left * 1440 ) / 2540 );
    rc.top    := round((r.Top * 1440 ) / 2540 );
    rc.right  := round((r.Right * 1440 ) / 2540 / fx );
    rc.bottom := round((r.Bottom * 1440 ) / 2540 / fy);

    rcPage := rc;
    SaveRect := rc;
    // print entire content
    chrg.cpMin := 0;
    chrg.cpMax := -1;
    MaxLen := GetPreciseTextLen(Self);

    SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0);
    // wParam = 0 : just measure Text-Size, don't print
    SendMessage(Self.Handle, EM_FORMATRANGE, 0, Longint(@Range));
    chrg.cpMin := 0;
    h:=rc.bottom-rc.top;
    rc := SaveRect;
    case align of
       rBottom   : rc.top    := SaveRect.Bottom-h;
       rCentered : rc.top    := SaveRect.top+
                              ((SaveRect.Bottom-SaveRect.top)-h) div 2;
    end;

    SendMessage(Self.Handle, EM_FORMATRANGE, 1, Longint(@Range));
    SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0);

    DeleteDC(DisplayDC);
  end;
end;






Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
Richedit Preview
    change liu chin (Jul 6 2004 11:29AM)

Can You Send to Me For Demo of "Richedit Preview" , Thank You.
Respond

Demo for your RichEdit PrintPreview
    Jayan Chandrasekhar (Mar 23 2002 7:47PM)

Hello,

Is it possible to provide a demo for this code of yours.  I am using RxRichEdit.  A Demo will be a big help.

Thanks in anticipation.

Best Regards.
Respond

RE: Demo for your RichEdit PrintPreview
change liu chin (Jul 1 2004 3:54PM)

Can You RichEdit Demo Sampile To me, Thank You.

Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


   


  Community Ad of
M. Shkolnik
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)