Norint eksportuoti TDataSet arba ataskaitą į PDF Delphi aplinkoje, losLab PDF biblioteka siūlo du kelius. PDFlibTableExport pritaiko bet kurį TDataSet — FireDAC užklausą, ClientDataSet, atmintyje esančią lentelę — į puslapiais suskirstytą PDF lentelę, o trys tiltai skiltyje Addons perduoda paruoštą FastReport, QuickReport arba ReportBuilder ataskaitą tam pačiam PDF rašytuvui. Abu sugeneruoja tikrą PDF be spausdintuvo tvarkyklės ir be matomo lango
Šios dvi problemos atrodo panašios, bet tokios nėra. DBGrid arba neapdorotos užklausos rezultatas neturi savo maketo, todėl jo eksportavimas reiškia naujo sukūrimą: stulpelių, antraščių, puslapių lūžių. FastReport arba ReportBuilder dokumentas jau turi sukurtą maketą, todėl jo eksportavimas reiškia ištikimą kažkieno kito piešimo komandų atkartojimą PDF erdvėje. losLab PDF biblioteka šiuos klausimus laiko atskiruose moduliuose būtent todėl, kad skiriasi jų gedimų režimai, o likusioje šio straipsnio dalyje apžvelgiamas kiekvienas iš jų ir vietos, kur jie nustoja būti patikimi
Kaip eksportuoti TDataSet į PDF Delphi aplinkoje?
PDFlibTableExport paverčia duomenų rinkinį lentelę vienu iškvietimu. Eksportuotojas vieną kartą pereina laukų sąrašą, automatiškai praleidžia dvejetainius blob laukus — ftBlob, ftGraphic, ftBytes ir panašūs neturi naudingo ląstelės teksto — sulygiuoja skaitinius stulpelius pagal dešinę ir nupiešia pasirinktines zebro juostas virš stilingos antraštės juostos. Viduje jis sukuria tinklelį naudodamas CreateTable, užpildo ląsteles su SetTableCellContent ir atvaizduoja su DrawTableRows, naudojant tą pačią viešą lentelės API, kurią valdytumėte rankiniu būdu. Patogus apvalkalas PDFlibExportDataSet sukonfigūruoja milimetrus ir viršutinį kairįjį koordinatės pradžios tašką už jus, zodžiu, iškvietėjui tereikia nurodyti puslapį
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'); // any TDataSet works here
PDF.SetOrigin(1);
PDF.SetMeasurementUnits(1); // millimetres
PDF.SetPageSize('A4');
PDF.AddStandardFont(4);
Options := DefaultTableExportOptions;
Options.Title := 'Customers';
Options.ColumnWidth := 32; // 11 fields fit on A4 at 32 mm
Options.RepeatHeader := True; // redraw the header on each page
PDFlibExportDataSet(PDF, MemTable, 'customers.pdf', Options);
finally
PDF.Free;
MemTable.Free;
end;
end;
Automatinis blob laukų praleidimas yra numatytasis nustatymas, o ne suvaržymas. Kai jums reikia kiekvieno lauko kontrolės — pasirinktinės stulpelio etiketės, siauresnio pločio arba vidinio rakto stulpelio, kuris nėra blob, atsisakymo — sukurkite TPDFlibTableExporter tiesiogiai ir prisijunkite prie jo OnFieldFilter įvykio, kuris suveikia vieną kartą kiekvienam laukui ir pateikia jums keičiamą specifikaciją. Nustatykite Include į False, kad atmestumėte lauką, arba nustatykite ColumnWidth ir DisplayLabel, kad pakeistumėte numatytuosius nustatymus. Šiame įvykyje taip pat galite atmesti platų memo stulpelį, kad jis neišpūstų puslapio
Puslapiavimas: piešimo būsenos perdavimas tarp puslapių
DrawTableRows perneša puslapiavimo būseną, o suprasti jos veikimo principą yra svarbiausia dalis. Jūs iškviečiate ją nurodydami pirmąją eilutę ir paskutiniąją eilutę; perdavus paskutinę eilutę mažesnę už 1, tai reiškia piešti iki lentelės pabaigos, ribojant jūsų nurodytu aukščiu. Funkcija grąžina aukštį, kurį ji iš tikrųjų nupiešė, o GetTableLastDrawnRow praneša apie paskutinę tilpusią eilutę. Ši pora yra būsena, kurią perduodate iš vieno puslapio į kitą: kai paskutinė nupiešta eilutė nesiekia bendro skaičiaus, atidarote naują puslapį ir tęsiate nuo eilutės po jos. Niekas nėra matuojama iš naujo — tęsinys prasideda tiksliai ten, kur baigėsi ankstesnis iškvietimas
// How the exporter continues a long table across pages
PageHeight := PDF.PageHeight;
Y := PageHeight - Options.Top;
Row := 1;
while Row <= TotalRows do
begin
DrawHeight := Y - Options.BottomMargin;
// Last row = 0 means "draw to the end", bounded by DrawHeight
PDF.DrawTableRows(TableID, Options.Left, Y, DrawHeight, Row, 0);
LastDrawn := PDF.GetTableLastDrawnRow(TableID);
if LastDrawn >= TotalRows then
Break; // the whole table fit on this page
if LastDrawn < Row then
Break; // safety: no forward progress, bail out
PDF.NewPage;
Row := LastDrawn + 1; // continue from the first undrawn row
Y := PageHeight - Options.Top;
end;
Cikle taip pat randasi pasikartojanti antraštė. Kiekviename tęstinumo puslapyje eksportuotojas pasirinktinai vėl nupiešia 1 eilutę — antraštę — prieš duomenų eilutes, ir naudoja aukštį, grąžintą to pirmojo DrawTableRows iškvietimo, kad pastumtų kūną po ja. Štai kodėl DrawTableRows grąžina aukštį, o ne kitos eilutės koordinatę: grąžinama vertė leidžia sudėti iš naujo nupieštą antraštę ir tęsiamą kūną neįrašant griežtai nei vieno iš jų dydžio
Kaip eksportuoti FastReport arba ReportBuilder ataskaitą į PDF?
Ataskaitų tiltai taiko priešingą požiūrį: jie niekada nekuria maketo iš naujo, jie jį atkuria. Kiekvienas tiltas prisijungia prie savo variklio ties variklio vietine eksportavimo jungtimi. PDFlibFRExport paveldi iš TfrxCustomExportFilter ir gauna FastReport memo, paveikslėlių, formų ir linijų objektus, paversdamas kiekvieną iš jų PDFlibPas primityvu. PDFlibRBDevice paveldi iš TppFileDevice ir pereina per ReportBuilder DrawCommand sąrašą. PDFlibQRExport pasirenka visiškai trečią kelią, kurį aprašo kitas skyrius. Visi trys veikia beekraniniu režimu, o tai ir yra pagrindinė priežastis naudoti juos serveryje
Beekranis režimas nėra nemokamas, o FastReport yra perspėjantis pavyzdys. TfrxReport.Export nukreipia per peržiūros puslapius, kurie kreipiasi į filtro savybę ShowDialog, o ši savybė pagal nutylėjimą paveldi reikšmę True. Kompiuterio be interaktyvaus darbalaukio modalinis langas grąžina atšaukimo rezultatą ir eksportas tyliai nepavyksta. Nustatykite ShowDialog į False prieš iškviesdami Export, ir ataskaita bus atvaizduojama tyliai. ReportBuilder turi panašius jungiklius — AllowPrintToFile ir ShowPrintDialog —, o QuickReport, kuris viską valdo per Prepare, dialogų slopinimo apskritai nereikia
var
Exporter: TPDFlibFRExport;
begin
Report.PrepareReport; // build the pages first
Exporter := TPDFlibFRExport.Create(nil);
try
Exporter.FileName := 'invoice.pdf';
Exporter.ShowDialog := False; // headless: skip the modal, no cancel
Report.Export(Exporter);
finally
Exporter.Free;
end;
end;
Trys varikliai, trys koordinačių sistemos
Kiekvienas tiltas atlieka savo koordinačių aritmetiką, nes kiekvienas variklis pasaulį matuoja skirtingai. PDFlibFRExport traktuoja FastReport objektų pozicijas kaip pikselius esant 96 PPI ir mastelį keičia santykiu 96/25.4, kad gautų milimetrus. PDFlibRBDevice nuskaito ReportBuilder piešimo komandas tūkstantosiomis milimetro dalimis ir dalija iš 1000 bei užsiregistruoja per ppRegisterDevice, todėl pakanka nustatyti ppReport.DeviceType reikšmę 'PDFlibPas' ir iškviesti Print, kad išvestis būtų nukreipta per jį. PDFlibQRExport koordinačių matematikos išvis neatlieka: paruoštas QuickReport puslapis jau yra EMF metafailas, zodžiu, tiltas išsaugo kiekvieną puslapį į srautą ir perduoda jį ImportEMFFromStream, leisdamas bibliotekos įrenginio konteksto ir metafailų atvaizdavimo keliui išdėstyti kiekvieną glifą ir taisyklę. Priešingai, FastReport ir ReportBuilder tiltai generuoja vietinius vektorinio piešimo primityvus ir vietinį tekstą
var
PDF: TPDFlib;
begin
PDF := TPDFlib.Create;
try
PDF.SetOrigin(1);
// Prepares the report and appends every page in one call; the bridge
// turns each page's EMF into PDF through ImportEMFFromStream.
PDFlibQRExportReport(PDF, QuickRep1, 'ledger.pdf');
finally
PDF.Free;
end;
end;
Kur baigiasi tikslumas
Žinokite ribas prieš perkeldami darbo eigą į šiuos tiltus. Duomenų rinkinio eksportuotojas tyliai atmeta dvejetainius stulpelius, todėl ataskaitai, kurioje turi būti rodomas įterptas paveikslėlis, reikia kitokio požiūrio nei paprastai lentelei. QuickReport kelias, kadangi eina per EMF, paverčia tekstą į vektorinius glifus — puslapis atrodo teisingai, tačiau jame nėra pasirenkamo ar ieškomo teksto ir nėra pažymėtos PDF struktūros prieinamumui užtikrinti. FastReport ir ReportBuilder išlaiko tikrą tekstą, tačiau tipizuoti apdorojimo įrankiai apima įprastus vaizdus — memo, paveikslėlį, formą, liniją — ir naudoja ribojantį rėmelį arba praleidžia egzotinius objektus, todėl ataskaita, kurioje naudojamas turtingas tekstas, brūkšniniai kodai ar gradientiniai užpildai, praras detales. Nieko iš to nėra defektas; tai tiesiog reali vertimo sluoksnio riba
Vienas operacinis perspėjimas yra svarbesnis už kitus. Nė vienas iš trijų variklių nėra pateikiamas „losLab PDF Library“ viduje, o tiltai yra sąmoningai neįtraukti į pagrindinį rinkinį — jie kompiuliuojasi tik iš projekto, kurio paieškos kelyje jau yra FastReport VCL 6.x, QuickReport 8 arba ReportBuilder 20. Metafailų ir DrawCommand sąsajos, į kurias jie orientuojasi, išliko stabilios keliose pagrindinėse variklio versijose, tačiau versijų suderinamumu turite pasirūpinti patys. Pasiekite tai ir šie du keliai apims visą spektrą, nuo ad-hoc DBGrid iškelties iki suprojektuotos sąskaitos faktūros. Lentelių eksportuotojas ir ataskaitų tiltai yra platinami kartu su losLab PDF Library, skirta Delphi ir C++Builder