這個 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 表格很有用。
直接繪製可以完全控制字型、顏色、邊框、分頁和摘要行,而無需依賴視覺化報表設計器。這對於伺服器端或批處理工具特別有用,因為輸出格式必須在不同機器上保持穩定。