For å eksportere en TDataSet eller en rapport til PDF i Delphi, tilbyr losLab PDF Library to metoder. PDFlibTableExport tilpasser enhver TDataSet — en FireDAC-spørring, et ClientDataSet, en tabell i minnet — til en paginert PDF-tabell, og tre broer under Addons overleverer en klargjort FastReport-, QuickReport- eller ReportBuilder-rapport til den samme PDF-skriveren. Begge produserer en ekte PDF uten skriverdriver og uten synlig vindu
De to problemene ser like ut, men er det ikke. En DBGrid eller et rått spørringsresultat har ingen egen layout, så å eksportere det betyr å finne opp en: kolonner, overskrifter, sideskift. Et FastReport- eller ReportBuilder-dokument har allerede en utformet layout, så å eksportere det betyr å trofast gjengi noen andres tegnekommandoer i PDF-rommet. losLab PDF Library holder disse oppgavene i separate enheter nettopp fordi feilmodusene er forskjellige, og resten av denne artikkelen går gjennom hver enkelt og hvor de slutter å være pålitelige
Hvordan eksporterer du en TDataSet til PDF i Delphi?
PDFlibTableExport gjør om et datasett til en tabell i ett enkelt kall. Eksporteren går gjennom feltlisten én gang, hopper over binære blob-felt automatisk — ftBlob, ftGraphic, ftBytes og lignende har ingen nyttig celletekst — høyrejusterer numeriske kolonner og tegner en valgfri sebrastripe over et stilisert overskriftsbånd. Under panseret bygger den rutenettet med CreateTable, fyller celler med SetTableCellContent og rendrer med DrawTableRows, det samme offentlige Table API-et som du ville styrt manuelt. Den praktiske wrapperen PDFlibExportDataSet konfigurerer millimeter og et topp-venstre-origo for deg, slik at oppkalleren bare trenger å oppgi en side
uses
Data.DB, FireDAC.Comp.Client, FireDAC.Stan.StorageBin,
PDFlibrary, PDFlibTableExport;
var
MemTable: TFDMemTable;
PDF: TPDFlib;
Options: TPDFlibTableExportOptions;
begin
MemTable := TFDMemTable.Create(nil);
PDF := TPDFlib.Create;
try
MemTable.LoadFromFile('customer.FDS'); // enhver TDataSet fungerer her
PDF.SetOrigin(1);
PDF.SetMeasurementUnits(1); // millimeter
PDF.SetPageSize('A4');
PDF.AddStandardFont(4);
Options := DefaultTableExportOptions;
Options.Title := 'Customers';
Options.ColumnWidth := 32; // 11 felt får plass på A4 ved 32 mm
Options.RepeatHeader := True; // tegn overskriften på nytt på hver side
PDFlibExportDataSet(PDF, MemTable, 'customers.pdf', Options);
finally
PDF.Free;
MemTable.Free;
end;
end;
Det automatiske hoppet over blob-felt er en standard, ikke en tvangstrøye. Når du trenger kontroll per felt — en tilpasset kolonneetikett, en smalere bredde, eller å utelate en intern nøkkelkolonne som ikke er en blob — oppretter du en TPDFlibTableExporter direkte og kobler deg til dens OnFieldFilter-hendelse, som utløses én gang per felt og gir deg en endringsbar spesifikasjon. Sett Include to False for å utelate feltet, eller angi ColumnWidth og DisplayLabel for å overstyre standardverdiene. Denne hendelsen er også der du ekskluderer en bred memo-kolonne som du ikke vil at skal blåse opp siden
Paginering: overføring av tegnetilstand mellom sider
DrawTableRows bærer pagineringstilstanden, og å forstå dens kontrakt er hele poenget. Du kaller den med en første rad og en siste rad; å sende en siste rad under 1 betyr å tegne til slutten av tabellen, begrenset av høyden du oppga. Funksjonen returnerer høyden den faktisk tegnet, og GetTableLastDrawnRow rapporterer den siste raden som fikk plass. Dette paret er tilstanden du overfører fra én side til den neste: når den siste tegnede raden er mindre enn totalen, åpner du en ny side og fortsetter fra raden etter. Ingenting måles på nytt — fortsettelsen starter akkurat der det forrige kallet slapp
// Hvordan eksportøren fortsetter en lang tabell over flere sider
PageHeight := PDF.PageHeight;
Y := PageHeight - Options.Top;
Row := 1;
while Row <= TotalRows do
begin
DrawHeight := Y - Options.BottomMargin;
// Siste rad = 0 betyr «tegn til slutten», begrenset av DrawHeight
PDF.DrawTableRows(TableID, Options.Left, Y, DrawHeight, Row, 0);
LastDrawn := PDF.GetTableLastDrawnRow(TableID);
if LastDrawn >= TotalRows then
Break; // hele tabellen fikk plass på denne siden
if LastDrawn < Row then
Break; // sikkerhet: ingen fremdrift, avbryt
PDF.NewPage;
Row := LastDrawn + 1; // fortsett fra den første utegnede raden
Y := PageHeight - Options.Top;
end;
Løkken er også der det gjentakende overskriftshodet lever. På hver fortsettelsesside tegner eksporteren valgfritt rad 1 igjen — overskriften — før dataradene, og den bruker høyden returnert av det første DrawTableRows-kallet til å forskyve hoveddelen under den. Dette er grunnen til at DrawTableRows returnerer en høyde i stedet for en koordinat for neste rad: returverdien er det som lar deg stable en nytegnet overskrift og den fortsettende hoveddelen uten å hardkode størrelsen på noen av dem
Hvordan eksporterer du en FastReport- eller ReportBuilder-rapport til PDF?
Rapportbroene bruker motsatt tilnærming: de finner aldri på en layout, de gjengir en. Hver bro kobles til sin motor ved motorens opprinnelige eksportgrensesnitt. PDFlibFRExport underklasser TfrxCustomExportFilter og mottar FastReports memo-, bilde-, figur- og linjeobjekter, og oversetter hvert av dem til en PDF Library for Delphi-primitiv. PDFlibRBDevice underklasser TppFileDevice og går gjennom ReportBuilders DrawCommand-liste. PDFlibQRExport tar en helt tredje vei, som dekkes i neste avsnitt. Alle tre kjører hodeløst, noe som er hele grunnen til å bruke dem på en server
Hodeløs kjøring er ikke gratis, og FastReport er et advarende eksempel. TfrxReport.Export ruter gjennom forhåndsvisningssidene, som konsulterer filterets ShowDialog-egenskap, og den egenskaper arver en standardverdi på True. På en maskin uten interaktivt skrivebord returnerer den modale dialogboksen et avbrutt-resultat, og eksporten mislykkes i det stille. Sett ShowDialog til False før du kaller Export, og rapporten rendres lydløst. ReportBuilder har de parallelle bryterne — AllowPrintToFile og ShowPrintDialog — og QuickReport, som driver alt gjennom Prepare, trenger ingen dialogundertrykkelse i det hele tatt
var
Exporter: TPDFlibFRExport;
begin
Report.PrepareReport; // bygg sidene først
Exporter := TPDFlibFRExport.Create(nil);
try
Exporter.FileName := 'invoice.pdf';
Exporter.ShowDialog := False; // headless: hopp over modalvinduet, ingen avbryt
Report.Export(Exporter);
finally
Exporter.Free;
end;
end;
Tre motorer, tre koordinatsystemer
Hver bro gjør sin egen koordinataritmetikk, fordi hver motor måler verden forskjellig. PDFlibFRExport behandler FastReport-objektposisjoner som piksler ved 96 PPI og skalerer med 96/25,4 for å nå millimeter. PDFlibRBDevice leser ReportBuilders tegnekommandoer i tusendels millimeter og deler på 1000, og den registrerer seg selv gjennom ppRegisterDevice, så å sette ppReport.DeviceType til 'PDF Library for Delphi' og kalle Print er nok til å rute utdataene gjennom den. PDFlibQRExport gjør ingen koordinatmatematikk i det hele tatt: en klargjort QuickReport-side er allerede en EMF-metafil, så broen lagrer hver side til en strøm og sender den til ImportEMFFromStream, og lar bibliotekets enhetskontekst- og metafilrendrings-bane plassere hver glyf og linje. FastReport- og ReportBuilder-broene sender derimot ut native vektortegningsprimitiver og native tekst
var
PDF: TPDFlib;
begin
PDF := TPDFlib.Create;
try
PDF.SetOrigin(1);
// Forbereder rapporten og legger til hver side i ett kall; broen
// gjør hver sides EMF om til PDF via ImportEMFFromStream.
PDFlibQRExportReport(PDF, QuickRep1, 'ledger.pdf');
finally
PDF.Free;
end;
end;
Hvor nøyaktigheten slutter
Kjenn grensene før du overlater en arbeidsflyt til disse broene. Datasetteksporteren utelater binære kolonner i det stille, så en rapport som må vise et innebygd bilde trenger en annen tilnærming enn en ren tabell. QuickReport-banen, fordi den går via EMF, baker tekst inn i vektorglyfer — siden ser riktig ut, men inneholder ingen velgbar eller søkbar tekst og ingen tagget PDF-struktur for universell utforming. FastReport og ReportBuilder beholder ekte tekst, men de spesifikke håndtererene dekker de vanlige visningene — memo, bilde, figur, linje — og faller tilbake til en avgrensningsboks eller hopper over de mer eksotiske, så en rapport som baserer seg på rik tekst, strekkoder eller gradientfyll vil miste detaljer. Ingenting av dette er en feil; det er den ærlige grensen for et oversettelseslag
Én driftsmessig advarsel er viktigere enn resten. Ingen av de tre motorene følger med losLab PDF Library, og broene er bevisst ekskludert fra hovedbyggingen — de kompilerer bare fra et prosjekt som allerede har FastReport VCL 6.x, QuickReport 8 eller ReportBuilder 20 i søkebanen sin. Grensesnittene for metafiler og DrawCommand som de retter seg mot har holdt seg stabile over flere store motorversjoner, men du har ansvaret for at versjonene samsvarer. Få det riktig, og de to banene dekker hele spekteret, fra en ad-hoc DBGrid-dump til en designet faktura. Tabelleksporteren og rapportbroene leveres begge med losLab PDF Library for Delphi og C++Builder