Этот пример компонента HotPDF преобразует записи базы данных в таблицу в формате PDF с постраничной нумерацией. Это компактный шаблон генерации отчетов: чтение строк из набора данных, отрисовка заголовка таблицы, вывод каждой строки в известной вертикальной позиции и добавление новой страницы, когда текущая страница заполнена.
В примере используется устаревший источник данных TTable, но логика PDF независима от этого уровня хранения. Тот же подход рендеринга можно использовать с FireDAC, ADO, наборами данных в памяти, результатами REST или любыми данными приложения, которые можно перечислять построчно.
Ключевой момент проектирования - разделение отрисовки строк и настройки страницы. PrintRow отрисовывает одну строку, PreparePage создает повторяющийся заголовок и метаданные страницы, а основной цикл управляет постраничной нумерацией. Такое разделение упрощает адаптацию примера для более широких таблиц, итогов, группировки или фирменных заголовков отчетов.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
program TableDemo; {$APPTYPE CONSOLE} { Reduce EXE size by disabling as much of RTTI as possible } {$IFDEF VER210} {$WEAKLINKRTTI ON} {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])} {$ENDIF} uses {$IFDEF VER230}System.Classes, System.SysUtils, Vcl.Graphics, DB, DBTables, {$ELSE} Classes, SysUtils, Graphics, DB, DBTables, {$ENDIF} HPDFDoc; var HotPDF: THotPDF; PageNum, VertPos: Integer; CustomerTable: TTable; Back: boolean; procedure PrintRow(Position: Integer; No, Company, Addr, City: AnsiString; ShowBackground: boolean); begin if ShowBackground then begin HotPDF.CurrentPage.SetRGBColor($FFF3DD); HotPDF.CurrentPage.Rectangle(50, Position, 520, 20); HotPDF.CurrentPage.Fill; HotPDF.CurrentPage.SetRGBColor(clBlack); end; HotPDF.CurrentPage.TextOut(70, Position, 0, No); HotPDF.CurrentPage.TextOut(110, Position, 0, Company); HotPDF.CurrentPage.TextOut(300, Position, 0, Addr); HotPDF.CurrentPage.TextOut(480, Position, 0, City); end; procedure PreparePage; begin HotPDF.CurrentPage.SetFont('Arial', [fsItalic], 10); HotPDF.CurrentPage.TextOut(50, VertPos, 0, 'customer.db' + ' Page' + AnsiString(IntToStr(PageNum))); HotPDF.CurrentPage.TextOut(480, VertPos, 0, AnsiString(DateTimeToStr(Now))); HotPDF.CurrentPage.MoveTo(50, VertPos + 15); HotPDF.CurrentPage.LineTo(570, VertPos + 15); HotPDF.CurrentPage.MoveTo(50, VertPos + 45); HotPDF.CurrentPage.LineTo(570, VertPos + 45); HotPDF.CurrentPage.Stroke; HotPDF.CurrentPage.SetFont('Times New Roman', [fsItalic, fsBold], 12); HotPDF.CurrentPage.SetRGBFillColor(clNavy); PrintRow(VertPos + 25, 'No', 'Company', 'Addr', 'City', false); HotPDF.CurrentPage.SetRGBFillColor(clBlack); Inc(VertPos, 20); end; begin CustomerTable := TTable.Create(nil); try CustomerTable.DatabaseName := 'DBDEMOS'; CustomerTable.TableName := GetCurrentDir + '\customer.db'; CustomerTable.Active := true; CustomerTable.First; HotPDF := THotPDF.Create(nil); try HotPDF.AutoLaunch := true; HotPDF.FileName := 'TableDemo.pdf'; HotPDF.PageLayout := plOneColumn; HotPDF.BeginDoc; HotPDF.CurrentPage.SetFont('Arial', [fsBold], 24); HotPDF.CurrentPage.TextOut(200, 20, 0, 'Customer report'); // Print PDF header PageNum := 1; VertPos := 60; PreparePage; // Table header Back := true; while (not(CustomerTable.Eof)) do begin Back := not(Back); if (VertPos > 700) then // If end of page then begin HotPDF.AddPage; // Add page, draw and print Inc(PageNum); // table header and set VertPos := 60; // new print position PreparePage; end; PrintRow(VertPos + 25, // print row from the current position AnsiString(CustomerTable.FieldValues['CustNo']), AnsiString(CustomerTable.FieldValues['Company']), AnsiString(CustomerTable.FieldValues['Addr1']), AnsiString(CustomerTable.FieldValues['City']), Back); Inc(VertPos, 20); CustomerTable.Next; end; HotPDF.EndDoc; finally HotPDF.Free; end; finally CustomerTable.Free; end; end. |
Что нужно адаптировать для использования в производственной среде.
- Замените пример таблицы DBDEMOS на набор данных или результат запроса приложения.
- Определите ширину столбцов на основе ожидаемых данных, а не жестко задавайте каждую координату x.
- Обрабатывайте длинный текст, обертывая или усекая поля перед отрисовкой строки.
- Повторяйте заголовки таблицы на каждой новой странице, чтобы экспортируемые отчеты оставались читаемыми.
- Сохраняйте поля страницы и высоту строк в именованных константах, чтобы изменения в макете были предсказуемыми.
Почему прямое рисование таблиц в PDF полезно.
Прямое рисование обеспечивает полный контроль над шрифтами, цветами, границами, переносами на новые страницы и сводными строками, не завися от визуального конструктора отчетов. Это особенно полезно для серверных или пакетных инструментов, где формат вывода должен оставаться стабильным на разных машинах.