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

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

unit RichEditPreview;
 interface
 uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, Printers, RichEdit, Menus, ComCtrls, ToolWin;
 type
  TPageOffset = record
  mStart, mEnd: Integer;
  rendRect: TRect;
  end;
  TPreviewForm = class(TForm)
  Panel1: TPanel;
  Panel2: TPanel;
  procedure FormCreate(Sender: TObject);
  procedure FormDestroy(Sender: TObject);
  procedure FormResize(Sender: TObject);
  private
  { Private-Deklarationen }
  public
  { Public-Deklarationen }
  PreviewPanel: TPanel;
  procedure DrawRichEdit;
  end;
  TPreviewPanel = class(TPanel)
  private
  public
  constructor Create(Owner: TComponent); override;
  destructor Destroy; override;
  procedure Paint; override;
  property Canvas;
  end;
 var
  PreviewForm: TPreviewForm;
 implementation
 uses Unit1, RxRichEd;
 {$R *.dfm}
 procedure TPreviewForm.FormCreate(Sender: TObject);
 begin
  PreviewPanel := TPreviewPanel.Create(Self);
  PreviewPanel.Parent := Self;
  PreviewPanel.Color := clWhite;
 end;
 procedure TPreviewForm.FormDestroy(Sender: TObject);
 begin
  if PreviewPanel <> nil then PreviewPanel.Free
 end;
 // 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);
 var
  wPage, hPage, wClient, hClient: integer;
 begin
  // 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
  begin
  wCLient := Panel2.ClientWidth;
  hClient := MulDiv(Panel2.ClientWidth, hPage, wPage);
  // center the page in the window
  PreviewPanel. := ((Panel2.ClientHeight - hClient) div 2) - Panel1.Height;
  end
  else
  begin
  // center the page in the window
  PreviewPanel.Left := (Panel2.ClientWidth - wClient) div 2;
  PreviewPanel. := Panel1.Height;
  end;
  // now set size of panel
 PreviewPanel.Width := wClient;
  PreviewPanel.Height := hClient
 end;
 // 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;
 var
  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;
 begin
  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
  begin
  Left := 0;
   := 0;
  Right := wTwips;
  Bottom := hTwips
  end;
  with rendRect do
  begin
  Left := 0;
   := 0;
  Right := pageRect.Right - (1440 * 4);
  Bottom := pageRect.Bottom - (1440 * 4)
  end;
  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;
  // , 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
  begin
  with TextLenEx do
  begin
  flags := GTL_DEFAULT;
  codepage := CP_ACP;
  end;
  lastOffset := SendMessage(Form1.Editor.Handle, EM_GETTEXTLENGTHEX,
  wParam(@TextLenEx), 0)
  end
  else
  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.
 SaveDC(hdcCanvas);
  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. := rendRect. + (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
  begin
  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)
  else
  SetLength(FPageOffsets, Length(FPageOffsets) + 1);
  FPageOffsets[High(FPageOffsets)] := po
  end;
  // 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. := 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);
  Finalize(FPageOffsets);
 end;
 (*****************************************************)
 (* Alles uber den Nachfahren von TPanel *)
 (*****************************************************)
 constructor TPreviewPanel.Create(Owner: TComponent);
 begin
  inherited Create(Owner);
 end;
 destructor TPreviewPanel.Destroy;
 begin
  inherited Destroy
 end;
 procedure TPreviewPanel.Paint;
 begin
  inherited Paint;
  PreviewForm.DrawRichEdit;
 end;
 end.

swissdelphicenter.ch

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...