Code:

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.Top := ((Panel2.ClientHeight - hClient) div 2) - Panel1.Height;

  end

  else

   begin

    // center the page in the window

   PreviewPanel.Left := (Panel2.ClientWidth - wClient) div 2;

    PreviewPanel.Top  := 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;

    Top := 0;

    Right := wTwips;

    Bottom := hTwips

  end;

  with rendRect do

   begin

    Left := 0;

    Top := 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;

  // 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

   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.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

   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.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);

  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.

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить