Postavljanje THotPDF komponente na formu u vrijeme dizajniranja prikladno je za brzi prototip, ali vezuje komponentu za životni vijek forme, što se rijetko traži u produkcijskom kodu. Generator izvješća koji se pokreće jednim klikom na gumb, pozadinska nit (service thread) koja obrađuje noćne izvoze u serijama, pomoćna klasa koja uopće nema formu: u svakoj od tih situacija želite da komponenta postoji točno onoliko koliko traje jedan PDF zadatak, a zatim da nestane. To znači alociranje tijekom izvođenja programa, što mijenja dvije stvari koje vrijedi razumjeti prije pisanja prvog retka koda: tko je vlasnik objekta, i kako se odvija čišćenje kada nešto pođe po zlu
Semantika vlasnika u VCL-u
Svaki konstruktor VCL komponente preuzima parametar Owner tipa TComponent*. Prosljeđivanje this (forme) registrira novi objekt u popisu komponenti u vlasništvu forme, pa ako se forma uništi dok je komponenta još živa, VCL će je automatski osloboditi. Prosljeđivanje nullptr znači da nema vlasnika: vi preuzimate isključivu odgovornost za pokazivač, i ništa ga neće očistiti umjesto vas ako se dogodi iznimka (exception) koja odmota stog prije vašeg eksplicitnog delete
Za jednokratni (one-shot) izvoz koji završava unutar jedne funkcije funkcioniraju obje mogućnosti, ali imaju različite načine kvara. Kada je this vlasnik, curenje memorije (leak) nemoguće je sve dok se forma u konačnici zatvori; uz nullptr, pokazivač mora dosegnuti blok __finally. U praksi, obrazac nullptr plus __finally je malo čišći za objekte kratkog vijeka trajanja jer granicu životnog vijeka čini odmah vidljivom te sprječava da forma gomila posjedovane objekte koji su trebali biti privremeni
Struktura otporna na iznimke (Exception-safe structure)
Generiranje PDF-a može propasti zbog razloga koji nemaju veze s API-jem: izlazni direktorij (output directory) dozvoljava samo čitanje, nedostaje datoteka s fontovima, tok podataka (stream) se ispire prerano, ili podaci koje dostavlja pozivatelj prelaze ograničenje duljine. Bez obzira na uzrok, proces čišćenja mora biti izvršen. U C++Builderu idomatski način za garanciju toga je korištenje bloka try/__finally:
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#pragma package(smart_init)
#pragma link "HPDFDoc"
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
THotPDF* Pdf = new THotPDF(nullptr);
try
{
Pdf->FileName = "output.pdf";
Pdf->Compression = cmFlateDecode;
Pdf->FontEmbedding = true;
Pdf->BeginDoc();
Pdf->CurrentPage->SetFont("Arial", TFontStyles(), 12);
Pdf->CurrentPage->TextOut(72, 720, 0, L"Hello from C++Builder");
Pdf->EndDoc();
}
__finally
{
delete Pdf;
}
}
Nekoliko stvari na tom popisu vrijedi istaknuti. Vlasnik je nullptr, čime je životni vijek eksplicitan. Compression i FontEmbedding su postavljeni prije BeginDoc: oboje su opcije na razini dokumenta koje HotPDF primjenjuje prilikom otvaranja dokumenta, a kasnije dodjeljivanje istih nema učinka. TextOut preuzima koordinate u točkama koje se mjere od donjeg lijevog kuta stranice, s time da se Y povećava prema gore; par vrijednosti 72, 720 postavlja tekst blizu gornjeg lijevog kuta stranice veličine "letter" (letter-size page) s jednom inčom lijeve margine. Brisanje pokazivača, naredba delete Pdf, u bloku __finally izvršava se neovisno o tome jesu li BeginDoc, iscrtavanje (drawing) ili EndDoc podigli iznimku ili ne
Izbjegavajte pozivanje bilo koje metode na pokazivaču Pdf nakon izvođenja delete. Ako se pokazivač pohrani u varijablu člana (member variable), postavite ga na nullptr neposredno nakon brisanja kako bi bilo koji slučajni kasniji pristup rezultirao čistim padom umjesto neprimjetnog oštećenja (silent corruption)
Konfiguracija projekta
C++Builder pronalazi THotPDF pomoću kombinacije putanja za uključivanje (include paths), putanja do biblioteka (library paths) i pragma direktive. Generirano zaglavlje (header) nalazi se pored HPDFDoc.pas u izvornom direktoriju HotPDF-a; dodajte taj direktorij u Project > Options > C++ Compiler > Include path. Direktiva #pragma link "HPDFDoc" poručuje linkeru da uključi prevedenu jedinicu (compiled unit) bez ručnog unošenja na popis u projektnoj datoteci. Ako koristite paket za radno okruženje (runtime package) umjesto statičkog povezivanja (static linking), prvo instalirajte HotPDF paket za dizajniranje i izvođenje; pragma direktiva i dalje vrijedi
Nemojte mijenjati ime jedinice HPDFDoc. C++Builder izvodi ime zaglavlja iz Pascal imena jedinice, pa preimenovanje datoteke ili korištenje pseudonima staze (path alias) unutar pragma direktive prekida pretraživanje tiho
Opseg (Scoping) i serijski poslovi
Za jedan izvoz koji je pokrenut od strane korisnika, lokalna varijabla ograničena na upravitelja događajima gumba (button handler) je pravi odgovor: stvorena je, korištena i izbrisana unutar jednog okvira poziva (call frame), i namjera je očita svakome tko će kasnije čitati kod. Alternativa u fazi dizajna (design-time) je opravdana kada ista forma upravlja kontinuiranim procesom rada (workflow), kao što je panel za pregled ispisa (print-preview) koji ponovno izrađuje dokument kad god korisnik promijeni neku postavku; u tom slučaju, održavanje komponente na životu uz ponovljeno pozivanje BeginDoc/EndDoc manje narušava performanse od opetovanog alociranja i oslobađanja objekata s gomile (heap)
Za masovne zadatke (batch jobs) koji generiraju brojne dokumente u nizu (sequence), korištenje po jednog THotPDF objekta za svaki dokument isplati se unatoč operativnim troškovima alokacije. Stanje (State) se ne prenosi s dokumenta na dokument ako ne postoji objekt koji bi ga zadržao, što eliminira jednu vrstu nestalnih bugova (intermittent bug) koje nikada ne morate ispravljati. Alociraj, izradi (generate), izbriši, ponovi
Jedno svojstvo koje se pojavljuje u nekoliko demo primjera HotPDF-a je AutoLaunch, koje automatski otvara stvorenu datoteku u sistemskom pregledniku PDF-a neposredno nakon poziva EndDoc. Korisno je za vrijeme pisanja prve skice izgleda. U produkcijskom okruženju preskočite ga: eksplicitno otvorite putanju (output path), potvrdite postojanje datoteke s veličinom većom od nula, zabilježite (log) ishod i dopustite procesu koji to poziva da odredi je li preglednik potreban. Pri masovnoj obradi AutoLaunch pokreće jedan prozor preglednika po dokumentu i blokirat će postupak na nekim sustavima dok se preglednik ne zatvori
Komponenta THotPDF i svi ovdje prikazani pozivi za iscrtavanje dio su HotPDF komponente za Delphi i C++Builder