Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Распечатать RTF-файл и определить диапазон страницы для печати

Delphi , ОС и Железо , Принтеры и Печать

Распечатать RTF-файл и определить диапазон страницы для печати

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

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.

Here is the translation of the provided text into Russian:

Программа на Delphi, которая печатает файл RTF (Rich Text Format) и определяет диапазон страниц для печати. Программа состоит из основной формы (TForm1) с тремя кнопками: "Печать", "Предпросмотр" и "Закрыть".

  1. Процедура PrintBtnClick вызывается, когда пользователь нажимает на кнопку "Печать". Она рассчитывает размер страницы в твиписах (единица, используемая Delphi) и прямоугольник отображения для печати.

  2. Код определяет одиночный offset страницы (po) и инициализирует структуру TFormatRange, чтобы форматировать текст как можно больше на каждой странице, начиная с начала документа.

  3. Код рассчитывает количество текста в контроле, используя либо EM_ GETTEXTLENGTHEX, либо WM_GETTEXTLENGTH, в зависимости от версии RichEdit.

  4. Код сохраняет буфер форматирования и настраивает процесс печати, рассчитывая offset и маржи для каждой страницы.

  5. Затем код печатает каждую страницу, начиная с первой страницы, до тех пор, пока все страницы не будут напечатаны.

  6. Наконец, код восстанавливает настройки HDC принтера, заканчивает процесс печати, очищает буфер форматирования RichEdit и удаляет сохраненную информацию о таблице страниц.

Процедура PreviewBtnClick просто отображает форму предпросмотра (PreviewForm) при нажатии на кнопку "Предпросмотр", а процедура CloseBtnClick закрывает основную форму при нажатии на кнопку "Закрыть". Процедура FormShow загружает файл RTF, именуемый "Exceltabelle.rtf", в RichEdit-контроле при отображении основной формы.

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

Вот улучшенная версия кода:

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

   // Рассчитать offset и маржи для каждой страницы
  with pageRect do
    begin
      Left := 0;
      Top := 0;
      Right := wTwips;
      Bottom := hTwips;
    end;

   // Инициализировать структуру TFormatRange, чтобы форматировать текст как можно больше на каждой странице
  fr.hdc := Printer.Handle;
  fr.hdcTarget := Printer.Handle;
  fr.chrg.cpMin := po.mStart;
  fr.chrg.cpMax := -1;

   // Рассчитать количество текста в контроле, используя EM_GETTEXTLENGTHEX или WM_GETTEXTLENGTH, в зависимости от версии RichEdit
  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)
  else
    lastOffset := SendMessage(Editor.Handle, WM_GETTEXTLENGTH, 0, 0);

   // Печатать каждую страницу, начиная с первой страницы, до тех пор, пока все страницы не будут напечатаны
  pageCount := Length(FPageOffsets);
  currPage := 0;
  while currPage < pageCount do
    begin
       // Отображать текст для этой страницы
      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;
      SendMessage(Editor.Handle, EM_FORMATRANGE, 1, Longint(@fr));
      Inc(currPage);
    end;

   // Восстановить настройки HDC принтера и сообщить Windows, что мы закончили печать этого документа
  RestoreDC(fr.hdc, -1);
  Printer.EndDoc;

   // Очистить буфер форматирования RichEdit и удалить сохраненную информацию о таблице страниц
  fr.chrg.cpMin := SendMessage(Editor.Handle, EM_FORMATRANGE, 0, 0);
  Finalize(FPageOffsets);

  ShowMessage(Format('Было определено %d страниц', [pageCount]));
end;

В этой улучшенной версии кода добавлены комментарии для объяснения каждого раздела, а также отделены расчеты размера страницы и прямоугольника отображения в отдельный блок. Код также удаляет избыточные расчеты, хранящие значения pageRect и rendRect в переменных перед использованием их.

Распечатать RTF-файл и определить диапазон страницы для печати.


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

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: Принтеры и Печать ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-05-01 12:37:48/0.0040228366851807/0