Карта сайта Kansoftware
Разработка программного обеспечения

Сделать предварительный просмотр для TRichEdit

Delphi , Компоненты и Классы , TMemo и TRichEdit

Сделать предварительный просмотр для TRichEdit

Оформил: DeeCo
Автор: http://www.swissdelphicenter.ch

unit RichEditPreview;


   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, ExtCtrls, Printers, RichEdit, Menus, ComCtrls, ToolWin;

   TPageOffset = record
     mStart, mEnd: Integer;
     rendRect: TRect;

   TPreviewForm = class(TForm)
     Panel1: TPanel;
     Panel2: TPanel;
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure FormResize(Sender: TObject);
     { Private-Deklarationen }
     { Public-Deklarationen }
     PreviewPanel: TPanel;
     procedure DrawRichEdit;

   TPreviewPanel = class(TPanel)

     constructor Create(Owner: TComponent); override;
     destructor Destroy; override;
     procedure Paint; override;
     property Canvas;

   PreviewForm: TPreviewForm;


 uses Unit1, RxRichEd;

 {$R *.dfm}

 procedure TPreviewForm.FormCreate(Sender: TObject);
   PreviewPanel := TPreviewPanel.Create(Self);
   PreviewPanel.Parent := Self;
   PreviewPanel.Color := clWhite;

 procedure TPreviewForm.FormDestroy(Sender: TObject);
   if PreviewPanel <> nil then PreviewPanel.Free

 // We want the TPreviewPanel to approximate the scaled dimensions of the printed page. 
// Whenever the parent 
// form is resized, we need to rescale and center the panel on the form. 
// To do this, add an OnResize event to 
// the form and add the following code: 

procedure TPreviewForm.FormResize(Sender: TObject);
    wPage, hPage, wClient, hClient: integer;
   // get the printer dimensions 
  wPage := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH);
   hPage := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);
   // get the client window dimensions. 
  hClient := Panel2.ClientHeight;
   // initially adjust width to match height 
  wClient := MulDiv(Panel2.ClientHeight, wPage, hPage);
   // if that doesn't fit, then do it the other way 
  if wClient > Panel2.ClientWidth then
     wCLient := Panel2.ClientWidth;
     hClient := MulDiv(Panel2.ClientWidth, hPage, wPage);
     // center the page in the window 
    PreviewPanel.Top := ((Panel2.ClientHeight - hClient) div 2) - Panel1.Height;
     // center the page in the window 
    PreviewPanel.Left := (Panel2.ClientWidth - wClient) div 2;
     PreviewPanel.Top  := Panel1.Height;
   // now set size of panel 
  PreviewPanel.Width  := wClient;
   PreviewPanel.Height := hClient

 // The DrawRichEdit() method renders the contents of 
// the control on the preview panel. 
// Much of the code is 
// very close to the code used to print the control in Part 2. 
// The first part of the method is identical to 
// the printing code: 

procedure TPreviewForm.DrawRichEdit;
    wPage, hPage, xPPI, yPPI, wTwips, hTwips, currPage: integer;
   pageRect, rendRect, frameRect: TRect;
   po: TPageOffset;
   fr: TFormatRange;
   lastOffset, xOffset, yOffset, xPrinterOffset, yPrinterOffset: integer;
   FPageOffsets: array of TPageOffset;
   TextLenEx: TGetTextLengthEx;
   hdcDesktop, hdcCanvas, hdcPrinter, xDesktopPPI, yDesktopPPI,
   xFactor, yFactor: integer;
   wPage := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH);
   hPage := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);
   xPPI := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
   yPPI := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
   wTwips := MulDiv(wPage, 1440, xPPI);
   hTwips := MulDiv(hPage, 1440, yPPI);
   with pageRect do
     Left := 0;
     Top := 0;
     Right := wTwips;
     Bottom := hTwips
   with rendRect do
     Left := 0;
     Top := 0;
     Right := pageRect.Right - (1440 * 4);
     Bottom := pageRect.Bottom - (1440 * 4)
   po.mStart := 0;
   // We will be using several device contexts (DCs), 
  // so let's go ahead and create variables for them. 
  hdcDesktop := GetWindowDC(GetDesktopWindow);
   hdcCanvas  := TPreviewPanel(PreviewPanel).Canvas.Handle;
   hdcPrinter := Printer.Handle;
   // Next, define and initialize a FORMATRANGE structure. 
  fr.hdc        := hdcDesktop;
   fr.hdcTarget  := hdcPrinter;
   fr.chrg.cpMin := po.mStart;
   fr.chrg.cpMax := -1;
   // We will need the size of the text in the control. 
  if RichEditVersion >= 2 then
     with TextLenEx do
       flags    := GTL_DEFAULT;
       codepage := CP_ACP;
     lastOffset := SendMessage(Form1.Editor.Handle, EM_GETTEXTLENGTHEX,
       wParam(@TextLenEx), 0)
      lastOffset := SendMessage(Form1.Editor.Handle, WM_GETTEXTLENGTH, 0, 0);
   // Clear the control's formatting buffer before rendering. 
  SendMessage(Form1.Editor.Handle, EM_FORMATRANGE, 0, 0);
   // Here is the tricky part. 
  // We need to scale the rendering DC to match the size of the printed page in 
  // printer device units. 
   SetMapMode(hdcCanvas, MM_TEXT);
   SetMapMode(hdcCanvas, MM_ANISOTROPIC);
   SetMapMode(hdcPrinter, MM_TEXT);
   SetWindowExtEx(hdcCanvas, pageRect.Right, pageRect.Bottom, nil);
   xDesktopPPI := GetDeviceCaps(hdcDesktop, LOGPIXELSX);
   yDesktopPPI := GetDeviceCaps(hdcDesktop, LOGPIXELSY);
   ScaleWindowExtEx(hdcCanvas, xDesktopPPI, 1440, yDesktopPPI, 1440, nil);
   SetViewportExtEx(hdcCanvas, PreviewPanel.ClientWidth, PreviewPanel.ClientHeight, nil);
   // Apparently, the Rich Edit control reduces the width of the 
  // rendering area by the amount of the left 
  // offset to the printable portion of the page when printing. 
  // This is a little odd to me because none of 
  // the Windows API GDI functions care whether you are printing 
  // within the printable portion of the page. 
  // Further, this occurs even though the rendering rectangle is 
  // already within the printable portion of the 
  // page.  Anyway, this does not seem to happen when the rendering 
  // DC is the screen so we need to manually 
  // adjust the rectangle ourselves. 
  xPrinterOffset  := MulDiv(GetDeviceCaps(hdcPrinter, PHYSICALOFFSETX), 1440, xPPI);
   yPrinterOffset  := MulDiv(GetDeviceCaps(hdcPrinter, PHYSICALOFFSETY), 1440, yPPI);
   rendRect.Left   := rendRect.Left + (xPrinterOffset shr 1);
   rendRect.Right  := rendRect.Right - xPrinterOffset - (xPrinterOFfset shr 1);
   rendRect.Top    := rendRect.Top + (yPrinterOffset shr 1);
   rendRect.Bottom := rendRect.Bottom - yPrinterOffset - (yPrinterOFfset shr 1);
   // Remember that we are hardcoding two-inch margins. 
  xOffset := MulDiv(PreviewPanel.ClientWidth shl 1, 1440, pageRect.Right);
   yOffset := MulDiv(PreviewPanel.ClientHeight shl 1, 1440, pageRect.Bottom);
   SetViewportOrgEx(hdcCanvas, xOffset, yOffset, nil);
   // Now we build the table of offsets. 
  // Note that we save the rendering rectangle returned by the format 
  // call.  When the rendering and target devices are the same 
  // (or the target device is set to zero), the 
  // returned rectangle is not really needed. 
  // In that case, you can simply ask the control to print to the 
  // original rendering rectangle.  However, when the devices are different, 
  // the returned rendering rectangle 
  // is sometimes larger than the requested rectangle. 
  // This must be a bug in the Rich Edit control.  We deal 
  // with it by saving the returned value to use when 
  // we actually render the control to the screen. 
  while ((fr.chrg.cpMin <> -1) and (fr.chrg.cpMin < lastOffset)) do
     fr.rc         := rendRect;
     fr.rcPage     := pageRect;
     po.mStart     := fr.chrg.cpMin;
     fr.chrg.cpMin := SendMessage(Form1.Editor.Handle, EM_FORMATRANGE, 0, Longint(@fr));
     po.mEnd       := fr.chrg.cpMin - 1;
     po.rendRect   := fr.rc;
     if High(FPageOffsets) = -1 then SetLength(FPageOffsets, 1)
        SetLength(FPageOffsets, Length(FPageOffsets) + 1);
     FPageOffsets[High(FPageOffsets)] := po
   // If we were writing a fully working preview function, 
  // we could use FPageOffsets.size() to determine how 
  // many pages had been formatted. 
  // We would then set currPage (below) to the page that we wanted to 
  // display. 
  // In this example, however, we are going to display only the first page. 
  currPage := 0;
   // Now we set the rendering device to the panel's canvas. 
  // Since we have not cleared the formatting buffer, 
  // the target device is not needed, so we set it to zero. 
  // Then we fill in the remaining parts of the 
  // FORMATRANGE structure with the values we saved in FPageOffsets. 
  // Finally, we render the text to the 
  // screen (WPARAM is non-zero). 
  fr.hdc := hdcCanvas;
   fr.hdcTarget  := 0;
   fr.rc := FPageOffsets[currPage].rendRect;
   fr.rcPage := pageRect;
   fr.chrg.cpMin := FPageOffsets[currPage].mStart;
   fr.chrg.cpMax := FPageOffsets[currPage].mEnd;
   fr.chrg.cpMin := SendMessage(Form1.Editor.Handle, EM_FORMATRANGE, 1, Longint(@fr));
   // As I mentioned, the text may be drawn outside of the rendering rectangle. 
  // To make that easier to see, 
  // let's draw a rectangle that shows where the rendering rectangle should be 
  SetMapMode(hdcCanvas, MM_TEXT);
   SetViewportOrgEx(hdcCanvas, 0, 0, nil);
   frameRect := rendRect;
   OffsetRect(frameRect, 1440 + 1440, 1440 + 1440);
   xFactor          := MulDiv(PreviewPanel.ClientWidth,
     (pageRect.Right - rendRect.Right) shr 1, pageRect.Right);
   yFactor          := MulDiv(PreviewPanel.ClientHeight,
     (pageRect.Bottom - rendRect.Bottom) shr 1, pageRect.Bottom);
   frameRect.Left   := xFactor;
   frameRect.Right  := PreviewPanel.ClientWidth - xFactor;
   frameRect.Top    := yFactor;
   frameRect.Bottom := PreviewPanel.ClientHeight - yFactor;
   Windows.FrameRect(hdcCanvas, frameRect, GetStockObject(BLACK_BRUSH));
   // To wrap up, we restore the panel's canvas to the original state, 
  // release the desktop DC, clear the Rich 
  // Edit control's formatting buffer, empty the page offset table, 
    and Close the DrawRichEdit() method.RestoreDC(hdcCanvas, - 1);
   ReleaseDC(GetDesktopWindow, hdcDesktop);
   SendMessage(Form1.Editor.Handle, EM_FORMATRANGE, 0, 0);

 (* Alles uber den Nachfahren von TPanel              *)

 constructor TPreviewPanel.Create(Owner: TComponent);
   inherited Create(Owner);

 destructor TPreviewPanel.Destroy;
   inherited Destroy

 procedure TPreviewPanel.Paint;
   inherited Paint;


Статья Сделать предварительный просмотр для TRichEdit раздела Компоненты и Классы TMemo и TRichEdit может быть полезна для разработчиков на Delphi и FreePascal.

Комментарии и вопросы

Ваше мнение или вопрос к статье в виде простого текста (Tag <a href=... Disabled). Все комментарии модерируются, модератор оставляет за собой право удалить непонравившейся ему комментарий.



Ваше имя


Введите код

Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.

:: Главная :: TMemo и TRichEdit ::



©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru Rambler's Top100
20.10.2021 01:07:05/0.01349401473999/0