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

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

Category: VCL

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.

 

printed from
www.swissdelphicenter.ch
developers knowledge base