Delphi'de bir TDataSet veya raporu PDF'e aktarmak için losLab PDF Library iki yol sunar. PDFlibTableExport herhangi bir TDataSet'i — bir FireDAC sorgusunu, bir ClientDataSet'i, bellek içi bir tabloyu — sayfalandırılmış bir PDF tablosuna uyarlar; Addons altındaki üç köprü ise hazırlanmış bir FastReport, QuickReport veya ReportBuilder raporunu aynı PDF yazıcısına iletir. Her ikisi de yazıcı sürücüsü ve görünür bir pencere olmadan gerçek bir PDF oluşturur
İki sorun benzer görünse de öyle değildir. Bir DBGrid veya ham sorgu sonucunun kendine ait bir düzeni yoktur, bu nedenle bunu dışa aktarmak bir düzen tasarlamak anlamına gelir: sütunlar, başlıklar, sayfa sonları. Bir FastReport veya ReportBuilder belgesi zaten tasarlanmış bir düzen taşır, dolayısıyla bunu dışa aktarmak başkasının çizim komutlarını PDF alanında aslına sadık kalarak yeniden oynatmak anlamına gelir. losLab PDF Library, hata modları farklı olduğu için bu konuları ayrı birimlerde tutar; bu makalenin geri kalanı her birini ve nerede güvenilir olmaktan çıktıklarını incelemektedir
Delphi'de bir TDataSet'i PDF'e nasıl aktarırsınız?
PDFlibTableExport tek bir çağrıda veri kümesini bir tabloya dönüştürür. Dışa aktarıcı alan listesini bir kez tarar, ikili blob alanlarını otomatik olarak atlar — ftBlob, ftGraphic, ftBytes ve benzerlerinin kullanışlı bir hücre metni yoktur —, sayısal sütunları sağa hizalar ve stillendirilmiş bir başlık bandı üzerine isteğe bağlı bir zebra şeridi çizer. Arka planda ızgarayı CreateTable ile oluşturur, hücreleri SetTableCellContent ile doldurur ve kendiniz yöneteceğiniz genel Tablo API'si ile aynı olan DrawTableRows ile işler. Kolaylık sarmalayıcısı PDFlibExportDataSet sizin için milimetre ve sol üst başlangıç noktasını yapılandırır, böylece çağıranın yalnızca bir sayfa sağlaması gerekir
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;
Otomatik blob atlama bir varsayılandır, bir kısıtlama değildir. Alan başına denetime ihtiyaç duyduğunuzda — özel bir sütun etiketi, daha dar bir genişlik veya blob olmayan dahili bir anahtar sütununun çıkarılması gibi — doğrudan bir TPDFlibTableExporter oluşturun ve alan başına bir kez tetiklenen ve size değiştirilebilir bir özellik sunan OnFieldFilter olayına bağlanın. Alanı çıkarmak için Include değerini False yapın veya varsayılanları geçersiz kılmak için ColumnWidth ve DisplayLabel özelliklerini ayarlayın. Bu olay, sayfanın aşırı büyümesini istemediğiniz geniş bir not (memo) sütununu hariç tuttuğunuz yerdir
Sayfalandırma: çizim durumunu sayfalar arasında aktarma
DrawTableRows sayfalandırma durumunu taşır og bunun sözleşmesini anlamak oyunun tamamıdır. İlk satır ve son satır ile çağırırsınız; 1'den küçük bir son satır geçmek, verdiğiniz yükseklikle sınırlı olarak tablonun sonuna kadar çizilmesi anlamına gelir. İşlev fiilen çizdiği yüksekliği döndürür ve GetTableLastDrawnRow sığan son satırı raporlar. Bu çift, bir sayfadan diğerine aktardığınız durumdur: çizilen son satır toplamın gerisinde kaldığında, yeni bir sayfa açar ve ondan sonraki satırdan devam edersiniz. Hiçbir şey yeniden ölçülmez — devam çağrısı bir önceki çağrının kaldığı yerden aynen devam eder
// 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;
Döngü aynı zamanda yinelenen başlığın bulunduğu yerdir. Her devam sayfasında dışa aktarıcı isteğe bağlı olarak veri satırlarından önce satır 1'i — başlığı — tekrar çizer ve altındaki gövdeyi kaydırmak için ilk DrawTableRows çağrısı tarafından döndürülen yüksekliği kullanır. DrawTableRows'un bir sonraki satır koordinatı yerine bir yükseklik döndürmesinin nedeni budur: dönüş değeri, yinelenen bir başlığı ve devam eden gövdeyi herhangi birinin boyutunu sabit kodlamadan üst üste yığmanıza olanak tanıyan şeydir
Bir FastReport veya ReportBuilder raporunu PDF'e nasıl aktarırsınız?
Rapor köprüleri tam tersi bir yaklaşım sergiler: asla bir düzen oluşturmazlar, mevcut olanı yeniden oynatırlar. Her köprü kendi motoruna motorun yerel dışa aktarma bağlantı noktasından bağlanır. PDFlibFRExport, TfrxCustomExportFilter'ı alt sınıflara ayırır ve FastReport'un not (memo), resim, şekil ve çizgi nesnelerini alarak her birini bir PDFlibPas primitiğine çevirir. PDFlibRBDevice, TppFileDevice'ı alt sınıflara ayırır og ReportBuilder'ın DrawCommand listesini tarar. PDFlibQRExport tamamen üçüncü bir yol izler ve bir sonraki bölümde ele alınmaktadır. Her üçü de arka planda (headless) çalışır; bu da sunucuda bunlara yönelmenin yegane nedenidir
Arka planda (headless) çalışmak zahmetsiz değildir ve FastReport buna ibretlik bir örnektir. TfrxReport.Export, filtrenin ShowDialog özelliğine başvuran önizleme sayfaları üzerinden yönlendirilir ve bu özellik varsayılan olarak True değerini devralır. Etkileşimli masaüstü olmayan bir makinede, modal iletişim kutusu bir iptal sonucu döndürür ve dışa aktarma sessizce başarısız olur. Export'u çağırmadan önce ShowDialog'u False olarak ayarladığınızda rapor sessizce işlenir. ReportBuilder da paralel anahtarlara sahiptir — AllowPrintToFile ve ShowPrintDialog — ve her şeyi Prepare aracılığıyla yürüten QuickReport'un ise iletişim kutusunu engellemeye hiç ihtiyacı yoktur
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;
Üç motor, üç koordinat sistemi
Her köprü kendi koordinat aritmetiğini yapar, çünkü her motor dünyayı farklı ölçer. PDFlibFRExport, FastReport nesne konumlarını 96 PPI'da piksel olarak ele alır ve milimetreye ulaşmak için 96/25.4 ile ölçeklendirir. PDFlibRBDevice, ReportBuilder'ın çizim komutlarını milimetrenin binde biri cinsinden okur ve 1000'e böler; ayrıca kendini ppRegisterDevice aracılığıyla kaydeder, bu nedenle ppReport.DeviceType değerini 'PDFlibPas' olarak ayarlayıp Print'i çağırmak, çıktıyı onun üzerinden yönlendirmek için yeterlidir. PDFlibQRExport hiç koordinat matematiği yapmaz: hazırlanmış bir QuickReport sayfası zaten bir EMF meta dosyasıdır, bu nedenle köprü her sayfayı bir akışa kaydeder ve ImportEMFFromStream'e besler, böylece kitaplığın cihaz bağlamı ve meta dosyası işleme yolu her glifi ve çizgiyi yerleştirir. FastReport ve ReportBuilder köprüleri ise buna karşılık yerel vektör çizim primitifleri ve yerel metin yayar
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;
Doğruluğun bittiği yer
Bir iş akışını bu köprülere teslim etmeden önce sınırları bilin. Veri kümesi dışa aktarıcısı ikili sütunları sessizce atlar, bu nedenle gömülü bir resmi göstermesi gereken bir raporun düz bir tablodan farklı bir yaklaşıma ihtiyacı vardır. QuickReport yolu, EMF üzerinden gittiği için metni vektör gliflerine dönüştürür — sayfa doğru görünür ancak seçilebilir veya aranabilir metin ile erişilebilirlik için etiketli PDF yapısı taşımaz. FastReport ve ReportBuilder gerçek metni korur, ancak yazılan işleyiciler yaygın görünümleri — not (memo), resim, şekil, çizgi — kapsar ve sınırlayıcı bir kutuya geri döner veya sıra dışı olanları atlar; bu nedenle zengin metin, barkodlar veya degrade dolgulara dayanan bir rapor ayrıntı kaybedecektir. Bunların hiçbiri bir kusur değildir; bir çeviri katmanının dürüst sınırıdır
Operasyonel bir uyarı diğerlerinden daha önemlidir. Üç motorun hiçbiri losLab PDF Library ile birlikte gelmez ve köprüler kasıtlı olarak ana derlemeden hariç tutulmuştur — yalnızca arama yolunda zaten FastReport VCL 6.x, QuickReport 8 veya ReportBuilder 20 bulunan bir projeden derlenirler. Hedefledikleri meta dosyası ve DrawCommand yüzeyleri birkaç ana motor sürümü boyunca kararlı kalmıştır, ancak sürüm eşleşmesi size aittir. Bunu doğru yaptığınızda, iki yol geçici bir DBGrid dökümünden tasarlanmış bir faturaya kadar tüm yelpazeyi kapsar. Tablo dışa aktarıcısı ve rapor köprüleri, Delphi ve C++Builder için losLab PDF Library ile birlikte gönderilir