Technisch artikel

Een HotPDF-component dynamisch maken en vrijgeven in C++Builder

· PDF-programmeren

De meeste HotPDF-voorbeelden plaatsen een component tijdens design time op een formulier. Dat is handig voor demo's, maar productiecode moet de PDF-component soms alleen voor een specifieke exportbewerking maken. Dynamische creatie is nuttig in servicemodules, rapporthelpers, batchtaken en formulieren waar de component niet gedurende de volledige levensduur van het formulier hoeft te bestaan.

Het basispatroon in C++Builder is een THotPDF-instantie alloceren, het uitvoerbestand en de documentopties configureren, de PDF genereren en de component vrijgeven wanneer de bewerking klaar is. Het voorbeeld hieronder toont de minimale workflow in een button handler.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include
#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* HotPDF1 = new THotPDF(this);
    HotPDF1->FileName = "HelloWorld.pdf";
    HotPDF1->AutoLaunch = true;      
    HotPDF1->BeginDoc(false);
    HotPDF1->CurrentPage->PrintText( 10, 10, 0, "Hello World!" );
    HotPDF1->EndDoc();
    HotPDF1->Free();
}

Eigendom en opschonen

De constructor ontvangt this als owner, zodat het formulier de component kan opruimen als die blijft bestaan. In dit korte voorbeeld wordt het object ook expliciet vrijgegeven na EndDoc. Houd in echte code het opschoonpad exception-safe: als PDF-generatie kan mislukken, plaats het werk in een try/__finally-blok of gebruik een kleine RAII-helper zodat Free() altijd wordt uitgevoerd.

Roep geen methoden meer aan op de component na Free(), en sla de pointer niet in een bredere scope op tenzij een ander deel van het formulier de levenscyclus echt bezit. Een lokale variabele is meestal de eenvoudigste keuze voor eenmalige PDF-exports.

Projectinstellingen

Het project moet de HotPDF-headers, bibliotheken en design/runtime packages kunnen vinden. Voeg de HotPDF include-directory toe aan het C++ include-pad en de library-directory aan het linkerzoekpad. Als het project HPDFDoc linkt, laat package- en unitnamen ongewijzigd zodat C++Builder de gegenereerde headers kan vinden.

Voor levering

  • Gebruik een absoluut of gevalideerd uitvoerpad wanneer bestanden buiten een demomap worden gegenereerd.
  • Roep BeginDoc en EndDoc in gebalanceerde paren aan.
  • Open de gegenereerde PDF in ten minste één externe viewer, niet alleen met AutoLaunch.
  • Log generatiefouten zodat support pad-, permissie-, font- en PDF-renderingproblemen kan onderscheiden.

Exception-safe structuur

Het voorbeeld houdt de code compact, maar een echte exportroutine moet exceptions tussen allocatie en cleanup afhandelen. PDF-generatie kan mislukken doordat de uitvoermap alleen-lezen is, een font niet wordt gevonden, een stream te vroeg is gesloten of gebruikersdata een onverwachte waarde bevat. Het opschoonpad mag niet afhangen van het succes van elke tekenaanroep.

Een praktische aanpak is de component direct vóór de export te maken en daarna in een gegarandeerd cleanup-blok vrij te geven. Zo blijft de levensduur van de component gekoppeld aan één PDF-taak. Als de applicatie veel documenten achter elkaar genereert, verkleint dit patroon ook de kans dat status uit het ene document in het volgende lekt.

Design-time versus runtime componenten

Een design-time component is eenvoudiger wanneer één formulier één voorspelbare exportworkflow bezit. Een runtime component is beter wanneer de applicatie meerdere tijdelijke exporters nodig heeft, instellingen dynamisch kiest of exportcode vanuit een helperklasse uitvoert in plaats van vanuit een formulier. De API-aanroepen zijn hetzelfde; het verschil is alleen wie het object bezit en hoe lang het leeft.

Vermijd in serverachtige of batchcode afhankelijkheid van AutoLaunch. Genereer het bestand, controleer dat het bestaat, leg het uitvoerpad vast en laat de aanroepende workflow bepalen of een viewer moet worden geopend.