A plasa un THotPDF pe un formular în timpul proiectării este suficient de bun pentru un prototip rapid, dar leagă componenta de durata de viață a formularului, ceea ce rareori este ceea ce își dorește codul de producție. Un generator de rapoarte care rulează o dată la fiecare clic de buton, un fir de execuție de serviciu care grupează exporturi peste noapte, o clasă auxiliară care nu are niciun formular: în fiecare dintre aceste situații doriți ca componenta să existe exact pe durata unei singure lucrări PDF și apoi să dispară. Asta înseamnă alocare la runtime și schimbă două lucruri pe care merită să le înțelegeți înainte de a scrie prima linie: cine deține obiectul și cum rulează curățarea atunci când ceva merge greșit
Semantica proprietarului în VCL
Fiecare constructor de componentă VCL primește un parametru Owner de tipul TComponent*. Transmiterea lui this (formularul) înregistrează noul obiect în lista de componente deținute a formularului, astfel încât, dacă formularul este distrus în timp ce componenta este încă activă, VCL o eliberează automat. Transmiterea lui nullptr înseamnă fără proprietar: vă asumați singura responsabilitate pentru pointer, iar nimic nu îl va curăța pentru dumneavoastră dacă o excepție derulează stiva înainte de delete-ul dumneavoastră explicit
Pentru un export unic care se finalizează într-o singură funcție, ambele variante funcționează, dar cele două au moduri de eșec diferite. Cu this ca proprietar, o scurgere de memorie este imposibilă atât timp cât formularul se închide în cele din urmă; cu nullptr, pointerul trebuie să ajungă într-un bloc __finally. În practică, modelul nullptr plus __finally este ușor mai curat pentru obiectele cu durată scurtă de viață, deoarece face vizibilă dintr-o privire granița duratei de viață și evită acumularea de către formular a unor obiecte deținute care erau menite să fie temporare
Structură sigură la excepții
Generarea PDF-ului poate eșua din motive care nu au nimic de-a face cu API-ul: directorul de ieșire este doar pentru citire, lipsește un fișier de font, un flux se golește prematur sau datele furnizate de apelant ating o limită de lungime. Indiferent de cauză, calea de curățare trebuie să ruleze. Modul idiomatic din C++Builder de a garanta acest lucru este 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;
}
}
Câteva lucruri din acest listing merită menționate. Proprietarul este nullptr, ceea ce face explicită durata de viață. Compression și FontEmbedding sunt setate înainte de BeginDoc: ambele sunt opțiuni la nivel de document pe care HotPDF le confirmă atunci când documentul se deschide, iar atribuirea lor ulterioară nu are niciun efect. TextOut primește coordonate în puncte măsurate din colțul din stânga jos al paginii, cu Y crescând în sus; perechea 72, 720 plasează textul lângă colțul din stânga sus al unei pagini de format letter, cu o margine stângă de un inch. delete Pdf din blocul __finally rulează indiferent dacă BeginDoc, desenarea sau EndDoc a generat o excepție sau nu
Evitați să apelați orice metodă pe Pdf după delete. Dacă pointerul este stocat într-o variabilă membru, setați-l la nullptr imediat după eliminare, astfel încât orice acces accidental ulterior să producă o cădere curată în loc de o corupere silențioasă
Configurarea proiectului
C++Builder localizează THotPDF printr-o combinație de căi de includere, căi de bibliotecă și o directivă pragma. Header-ul generat se află alături de HPDFDoc.pas în directorul sursă HotPDF; adăugați acel director la Project > Options > C++ Compiler > Include path. Directiva #pragma link "HPDFDoc" îi spune linker-ului să includă unitatea compilată fără a o lista manual în fișierul proiectului. Dacă folosiți pachetul runtime în loc de linkare statică, instalați mai întâi pachetele de proiectare și runtime HotPDF; pragma se aplică în continuare
Păstrați neschimbat numele unității HPDFDoc. C++Builder derivă numele header-ului din numele unității Pascal, astfel încât redenumirea fișierului sau folosirea unui alias de cale în pragma întrerupe silențios căutarea
Domeniul de vizibilitate și lucrările cu mai multe documente
Pentru un singur export declanșat de o acțiune a utilizatorului, o variabilă locală cu domeniul de vizibilitate limitat la handler-ul de buton este răspunsul corect: este creată, folosită și distrusă în cadrul unui singur cadru de apel, iar intenția este evidentă pentru oricine citește codul mai târziu. Alternativa la momentul proiectării este justificată atunci când același formular conduce un flux de lucru continuu, cum ar fi un panou de previzualizare a tipăririi care reconstruiește documentul de fiecare dată când utilizatorul modifică o setare; în acest caz, menținerea componentei active și apelarea repetată a BeginDoc/EndDoc este mai puțin disruptivă decât alocarea și eliberarea repetată a unor obiecte pe heap
Pentru lucrările în lot care produc multe documente în succesiune, limitarea unui THotPDF la un singur document merită costul suplimentar de alocare. Starea nu se transmite între documente dacă nu există niciun obiect care să o transporte, iar aceasta este o clasă de bug intermitent pe care nu va trebui niciodată să o depanați. Alocați, generați, ștergeți, repetați
O proprietate care apare în mai multe demo-uri HotPDF este AutoLaunch, care deschide fișierul generat în vizualizatorul PDF implicit al sistemului imediat după EndDoc. Este utilă în timp ce scrieți prima variantă a unui layout. În producție, evitați-o: deschideți explicit calea de ieșire, verificați că fișierul există și are o dimensiune diferită de zero, înregistrați rezultatul în jurnal și lăsați fluxul de lucru apelant să decidă dacă un vizualizator este relevant. Într-o lucrare în lot, AutoLaunch lansează câte o fereastră de vizualizator pentru fiecare document și va bloca procesul pe unele sisteme, așteptând închiderea vizualizatorului
Componenta THotPDF și toate apelurile de desenare prezentate aici fac parte din HotPDF Delphi Component pentru Delphi și C++Builder