Het plaatsen van een THotPDF op een formulier tijdens ontwerptijd is prima voor een snel prototype, maar het koppelt de component aan de levensduur van het formulier, wat zelden is wat productiecode vereist. Een rapportgenerator die één keer per knopklik draait, een servicethread die nachtelijke exports verwerkt, een helperklasse die helemaal geen formulier heeft: in elk van die situaties wilt u dat de component precies voor de duur van één PDF-taak bestaat en dan verdwijnt. Dat betekent runtime-toewijzing, en het verandert twee dingen die het waard zijn om te begrijpen voordat u de eerste regel schrijft: wie is de eigenaar van het object, en hoe wordt er opgeschoond als er iets misgaat
Eigenaarssemantiek in VCL
Elke VCL component-constructor neemt een Owner parameter van het type TComponent*. Het doorgeven van this (het formulier) registreert het nieuwe object in de lijst van componenten die eigendom zijn van het formulier, dus als het formulier wordt vernietigd terwijl de component nog leeft, geeft VCL het automatisch vrij. Het doorgeven van nullptr betekent geen eigenaar: u neemt als enige de verantwoordelijkheid voor de pointer, en niets zal het voor u opschonen als een uitzondering de stack afwikkelt vóór uw expliciete delete
Voor een eenmalige export die binnen een enkele functie wordt voltooid, werkt beide keuzes, maar de twee hebben verschillende faalwijzen. Met this als eigenaar is een lek onmogelijk zolang het formulier uiteindelijk sluit; met nullptr moet de pointer een __finally blok bereiken. In de praktijk is het nullptr plus __finally patroon iets schoner voor kortlevende objecten, omdat het de levensduurgrens in één oogopslag zichtbaar maakt en voorkomt dat het formulier eigen objecten ophoopt die als tijdelijk waren bedoeld
Uitzonderingsveilige structuur
PDF-generatie kan falen om redenen die niets met de API te maken hebben: de uitvoermap is alleen-lezen, een lettertypebestand ontbreekt, een stream spoelt voortijdig door, of door de aanroeper verstrekte gegevens bereiken een lengtelimiet. Wat de oorzaak ook is, het opschoonpad moet draaien. De idiomatische C++Builder-manier om dat te garanderen is 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;
}
}
Een paar dingen in die code zijn de moeite waard om te benadrukken. De eigenaar is nullptr, wat de levensduur expliciet maakt. Compression en FontEmbedding worden ingesteld vóór BeginDoc: beide zijn opties op documentniveau die HotPDF vastlegt wanneer het document opent, en het toewijzen ervan daarna heeft geen effect. TextOut neemt coördinaten in punten gemeten vanaf de linkerbenedenhoek van de pagina, Y neemt naar boven toe; het paar 72, 720 plaatst tekst vlakbij de linkerbovenhoek van een Letter-formaat pagina met een linkermarge van één inch. De delete Pdf in het __finally blok wordt uitgevoerd ongeacht of BeginDoc, het tekenen, of EndDoc een uitzondering heeft opgeworpen of niet
Vermijd het aanroepen van een methode op Pdf na delete. Als de pointer is opgeslagen in een lidvariabele, stel deze dan onmiddellijk na verwijdering in op nullptr, zodat elke onbedoelde latere toegang een zuivere crash oplevert in plaats van stille corruptie
Projectconfiguratie
C++Builder vindt THotPDF via een combinatie van include-paden, bibliotheekpaden en een pragma-richtlijn. De gegenereerde header bevindt zich naast HPDFDoc.pas in de HotPDF-bronmap; voeg die map toe aan Project > Options > C++ Compiler > Include path. De #pragma link "HPDFDoc" richtlijn vertelt de linker om de gecompileerde unit binnen te halen zonder deze handmatig in het projectbestand op te sommen. Als u het runtimepakket gebruikt in plaats van statische koppeling, installeer dan eerst de HotPDF-ontwerp- en runtimepakketten; de pragma is nog steeds van toepassing
Houd de unit-naam HPDFDoc ongewijzigd. C++Builder leidt de headernaam af van de Pascal unit-naam, dus het hernoemen van het bestand of het gebruiken van een pad-alias in de pragma breekt de opzoeking in stilte af
Scoping en multi-document taken
Voor een enkele export geactiveerd door gebruikersactie, is een lokale variabele met scope in de knop-handler het juiste antwoord: deze wordt gemaakt, gebruikt en vernietigd binnen één callframe, en de intentie is duidelijk voor iedereen die de code later leest. Het ontwerptijd-alternatief is gerechtvaardigd wanneer hetzelfde formulier een continue workflow aanstuurt, zoals een afdrukvoorbeeldpaneel dat het document opnieuw opbouwt telkens wanneer de gebruiker een instelling wijzigt; in dat geval is het in leven houden van de component en het herhaaldelijk aanroepen van BeginDoc/EndDoc minder verstorend dan het herhaaldelijk toewijzen en vrijgeven van heap-objecten
Voor batch-taken die veel documenten na elkaar produceren, is het de moeite waard om één THotPDF per document te scopen vanwege de toewijzings-overhead. Status wordt niet overgedragen tussen documenten als er geen object is om het over te dragen, en dat is een klasse van intermitterende bugs die u nooit hoeft te debuggen. Toewijzen, genereren, verwijderen, herhalen
Een eigenschap die in verschillende HotPDF-demo's voorkomt, is AutoLaunch, dat het gegenereerde bestand onmiddellijk na EndDoc in de PDF-viewer van het systeem opent. Het is nuttig tijdens het schrijven van de eerste opzet van een lay-out. Sla het in productie over: open het uitvoerpad expliciet, verifieer dat het bestand bestaat en een grootte groter dan nul heeft, log het resultaat, en laat de aanroepende workflow beslissen of een viewer relevant is. In een batch-taak lanceert AutoLaunch één viewervenster per document en zal het proces op sommige systemen blokkeren in afwachting van het sluiten van de viewer
De THotPDF component en alle hier getoonde tekenaanroepen maken deel uit van de HotPDF Component voor Delphi en C++Builder