RichEdit的预览

字体大小: 中小 标准 ->行高大小: 标准
show a preview for a TRichEdit/ TRxRichEdit?

Author: Robert Dunn ,http://home.att.net/~robertdunn/Yacs.html

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

------------------------------------------------------------------------------

...print a rtf file and specify a page range to be printed?

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, RichEdit, RxRichEd, ExtCtrls, Printers;

type

TPageOffset = record

mStart,

mEnd: Integer;

rendRect: TRect;

end;

TForm1 = class(TForm)

Panel1: TPanel;

Editor: TRxRichEdit;

PrintBtn: TButton;

PreviewBtn: TButton;

CloseBtn: TButton;

procedure PrintBtnClick(Sender: TObject);

procedure PreviewBtnClick(Sender: TObject);

procedure CloseBtnClick(Sender: TObject);

procedure FormShow(Sender: TObject);

private

{ Private-Deklarationen }

public

{ Public-Deklarationen }

end;

var

Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.PrintBtnClick(Sender: TObject);

var

wPage, hPage, xPPI, yPPI, wTwips, hTwips: integer;

pageRect, rendRect: TRect;

po: TPageOffset;

fr: TFormatRange;

lastOffset, currPage, pageCount: integer;

xOffset, yOffset: integer;

FPageOffsets: array of TPageOffset;

TextLenEx: TGetTextLengthEx;

firstPage: boolean;

begin

//First, get the size of a printed page in printer device units

wPage := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH);

hPage := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);

//Next, get the device units per inch for the printer

xPPI := GetDeviceCaps(Printer.Handle, LOGPIXELSX);

yPPI := GetDeviceCaps(Printer.Handle, LOGPIXELSY);

//Convert the page size from device units to twips

wTwips := MulDiv(wPage, 1440, xPPI);

hTwips := MulDiv(hPage, 1440, yPPI);

//Save the page size in twips

with pageRect do

begin

Left := 0;

Top := 0;

Right := wTwips;

Bottom := hTwips

end;

//Next, calculate the size of the rendering rectangle in twips

//Rememeber - two inch margins are hardcoded, so the below code

//reduces the width of the output by four inches

with rendRect do

begin

Left := 0;

Top := 0;

Right := pageRect.Right - (1440 * 4);

Bottom := pageRect.Bottom - (1440 * 4)

end;

//Define a single page and set starting offset to zero

po.mStart := 0;

//Define and initialize a TFormatRange structure. This structure is passed

//to the TRichEdit with a request to format as much text as will fit on a

//page starting with the chrg.cpMin offset and ending with the chrg.cpMax.

//Initially, we tell the RichEdit control to start at the beginning

//(cpMin = 0) and print as much as possible (cpMax = -1). We also tell it

//to render to the printer

with fr do

begin

hdc := Printer.Handle;

hdcTarget := Printer.Handle;

chrg.cpMin := po.mStart;

chrg.cpMax := -1;

end;

//In order to recognize when the last page is rendered, we need to know how

//much text is in the control.

if RichEditVersion >= 2 then

begin

with TextLenEx do

begin

flags := GTL_DEFAULT;

codepage := CP_ACP;

end;

lastOffset := SendMessage(Editor.Handle, EM_GETTEXTLENGTHEX, wParam(@TextLenEx), 0)

end

else

lastOffset := SendMessage(Editor.Handle, WM_GETTEXTLENGTH, 0, 0);

//As a precaution, clear the formatting buffer

SendMessage(Editor.Handle, EM_FORMATRANGE, 0, 0);

//Printers frequently cannot print at the absolute top-left position on the

//page. In other words, there is usually a minimum margin on each edge of the

//page. When rendering to the printer, RichEdit controls adjust the top-left

//corner of the rendering rectangle for the amount of the page that is

//unprintable. Since we are printing with two-inch margins, we are presumably

//already within the printable portion of the physical page.

SaveDC(fr.hdc);

SetMapMode(fr.hdc, MM_TEXT);

xOffset := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);

yOffset := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);

xOffset := xOffset + MulDiv(1440 + 1440, xPPI, 1440);

yOffset := yOffset + MulDiv(1440 + 1440, yPPI, 1440);

SetViewportOrgEx(fr.hdc, xOffset, yOffset, nil);

//Now we build a table of page entries, one entry for each page that would be

//printed.

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(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;

pageCount := Length(FPageOffsets);

ShowMessage(Format('Es wurde %d Seiten ermittelt', [pageCount]));

SendMessage(Editor.Handle, EM_FORMATRANGE, 0, 0);

RestoreDC(fr.hdc, - 1);

//Now, we are almost ready to actually print.

Printer.BeginDoc;

fr.hdc := Printer.Handle;

fr.hdcTarget := Printer.Handle;

SaveDC(fr.hdc);

SetViewportOrgEx(fr.hdc, xOffset, yOffset, nil);

//Ok, here we go to print

firstPage := True;

//At this point you can select from page and to page

currPage := 0; //Print from the first page

pageCount := 1; //Only One page for testing

while (currPage < pageCount) do

begin

if firstPage then firstPage := False

else

Printer.NewPage;

SetViewportOrgEx(fr.hdc, xOffset, yOffset, nil);

fr.rc := FPageOffsets[currPage].rendRect;

fr.rcPage := pageRect;

fr.chrg.cpMin := FPageOffsets[currPage].mStart;

fr.chrg.cpMax := FPageOffsets[currPage].mEnd;

fr.chrg.cpMin := SendMessage(Editor.Handle, EM_FORMATRANGE, 1, Longint(@fr));

Inc(currPage);

end;

//At this point, we have finished rendering the contents of the RichEdit

//control. Now we restore the printer's HDC settings and tell Windows that

//we are through printing this document

RestoreDC(fr.hdc, - 1);

Printer.EndDoc;

//Finally, we clear the RichEdit control's formatting buffer and delete

//the saved page table information

fr.chrg.cpMin := SendMessage(Editor.Handle, EM_FORMATRANGE, 0, 0);

Finalize(FPageOffsets);

//That's it

end;

procedure TForm1.PreviewBtnClick(Sender: TObject);

begin

PreviewForm.ShowModal

end;

procedure TForm1.CloseBtnClick(Sender: TObject);

begin

Close

end;

procedure TForm1.FormShow(Sender: TObject);

begin

Editor.Lines.LoadFromFile('Exceltabelle.rtf');

end;

end.

此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/68018.html