Το να αφήσετε ένα THotPDF πάνω σε μια φόρμα κατά τον σχεδιασμό είναι μια χαρά για ένα γρήγορο πρωτότυπο, όμως δένει το στοιχείο με τη διάρκεια ζωής της φόρμας, κάτι που σπάνια θέλει ο κώδικας παραγωγής. Μια γεννήτρια αναφορών που τρέχει μία φορά ανά πάτημα κουμπιού, ένα νήμα υπηρεσίας που ομαδοποιεί νυχτερινές εξαγωγές, μια βοηθητική κλάση που δεν έχει καθόλου φόρμα: σε καθεμία από αυτές τις περιπτώσεις θέλετε το στοιχείο να υπάρχει ακριβώς για τη διάρκεια μίας εργασίας PDF και μετά να εξαφανίζεται. Αυτό σημαίνει δέσμευση στον χρόνο εκτέλεσης, και αλλάζει δύο πράγματα που αξίζει να καταλάβετε πριν γράψετε την πρώτη γραμμή: ποιος κατέχει το αντικείμενο, και πώς εκτελείται ο καθαρισμός όταν κάτι πάει στραβά
Σημασιολογία του owner στη VCL
Κάθε constructor στοιχείου της VCL δέχεται μια παράμετρο Owner τύπου TComponent*. Περνώντας το this (τη φόρμα) καταχωρείτε το νέο αντικείμενο στη λίστα των κατεχόμενων στοιχείων της φόρμας, ώστε αν η φόρμα καταστραφεί ενώ το στοιχείο είναι ακόμη ζωντανό, η VCL το αποδεσμεύει αυτόματα. Περνώντας nullptr σημαίνει ότι δεν υπάρχει owner: αναλαμβάνετε αποκλειστικά την ευθύνη του δείκτη, και τίποτα δεν θα τον καθαρίσει για λογαριασμό σας αν μια εξαίρεση ξετυλίξει τη στοίβα πριν από το ρητό σας delete
Για μια εξαγωγή μίας χρήσης που ολοκληρώνεται μέσα σε μία συνάρτηση, οποιαδήποτε από τις δύο επιλογές λειτουργεί, αλλά έχουν διαφορετικούς τρόπους αστοχίας. Με το this ως owner, η διαρροή είναι αδύνατη εφόσον η φόρμα τελικά κλείσει· με nullptr, ο δείκτης πρέπει να φτάσει σε ένα μπλοκ __finally. Στην πράξη, το μοτίβο nullptr συν __finally είναι ελαφρώς καθαρότερο για βραχύβια αντικείμενα, επειδή κάνει το όριο της διάρκειας ζωής ορατό με μια ματιά και αποφεύγει να συσσωρεύει η φόρμα κατεχόμενα αντικείμενα που προορίζονταν να είναι προσωρινά
Δομή ασφαλής ως προς τις εξαιρέσεις
Η παραγωγή PDF μπορεί να αποτύχει για λόγους που δεν έχουν καμία σχέση με το API: ο κατάλογος εξόδου είναι μόνο για ανάγνωση, λείπει ένα αρχείο γραμματοσειράς, μια ροή εκκενώνεται πρόωρα, ή τα δεδομένα που έδωσε ο καλών χτυπούν κάποιο όριο μήκους. Όποια και αν είναι η αιτία, η διαδρομή καθαρισμού πρέπει να εκτελεστεί. Ο ιδιωματικός τρόπος του C++Builder για να το εγγυηθείτε αυτό είναι το 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;
}
}
Μερικά σημεία σε αυτή την καταχώριση αξίζει να τονιστούν. Ο owner είναι nullptr, κάνοντας τη διάρκεια ζωής ρητή. Τα Compression και FontEmbedding ορίζονται πριν από το BeginDoc: και τα δύο είναι επιλογές σε επίπεδο εγγράφου που το HotPDF οριστικοποιεί όταν ανοίγει το έγγραφο, και η ανάθεσή τους αργότερα δεν έχει καμία επίδραση. Το TextOut δέχεται συντεταγμένες σε σημεία μετρημένες από την κάτω αριστερή γωνία της σελίδας, με το Y να αυξάνεται προς τα πάνω· το ζεύγος 72, 720 τοποθετεί το κείμενο κοντά στην επάνω αριστερή γωνία μιας σελίδας μεγέθους letter με περιθώριο μίας ίντσας αριστερά. Το delete Pdf στο μπλοκ __finally εκτελείται είτε το BeginDoc, η σχεδίαση ή το EndDoc ήγειραν εξαίρεση είτε όχι
Αποφύγετε να καλέσετε οποιαδήποτε μέθοδο στο Pdf μετά το delete. Αν ο δείκτης αποθηκεύεται σε μεταβλητή μέλους, θέστε τον σε nullptr αμέσως μετά τη διαγραφή, ώστε κάθε τυχαία μεταγενέστερη πρόσβαση να παράγει ένα καθαρό crash αντί για σιωπηλή αλλοίωση
Ρύθμιση του έργου
Ο C++Builder εντοπίζει το THotPDF μέσω ενός συνδυασμού από include paths, library paths και μια οδηγία pragma. Η παραγόμενη κεφαλίδα βρίσκεται δίπλα στο HPDFDoc.pas στον κατάλογο πηγαίου κώδικα του HotPDF· προσθέστε αυτόν τον κατάλογο στο Project > Options > C++ Compiler > Include path. Η οδηγία #pragma link "HPDFDoc" λέει στον linker να ενσωματώσει τη μεταγλωττισμένη μονάδα χωρίς να την καταχωρίσετε χειροκίνητα στο αρχείο του έργου. Αν χρησιμοποιείτε το runtime package αντί για στατική σύνδεση, εγκαταστήστε πρώτα τα design και runtime packages του HotPDF· η pragma εξακολουθεί να ισχύει
Διατηρήστε το όνομα μονάδας HPDFDoc αμετάβλητο. Ο C++Builder παράγει το όνομα της κεφαλίδας από το όνομα της μονάδας Pascal, οπότε η μετονομασία του αρχείου ή η χρήση ψευδωνύμου διαδρομής στην pragma χαλάει σιωπηλά την αναζήτηση
Εμβέλεια και εργασίες πολλαπλών εγγράφων
Για μία μεμονωμένη εξαγωγή που πυροδοτείται από ενέργεια του χρήστη, μια τοπική μεταβλητή με εμβέλεια τον χειριστή του κουμπιού είναι η σωστή απάντηση: δημιουργείται, χρησιμοποιείται και καταστρέφεται μέσα σε ένα πλαίσιο κλήσης, και η πρόθεση είναι προφανής σε όποιον διαβάσει τον κώδικα αργότερα. Η εναλλακτική του χρόνου σχεδίασης δικαιολογείται όταν η ίδια φόρμα οδηγεί μια συνεχή ροή εργασίας, όπως ένας πίνακας προεπισκόπησης εκτύπωσης που ξαναχτίζει το έγγραφο κάθε φορά που ο χρήστης αλλάζει μια ρύθμιση· σε αυτή την περίπτωση, το να κρατάτε το στοιχείο ζωντανό και να καλείτε επανειλημμένα BeginDoc/EndDoc είναι λιγότερο ενοχλητικό από το να δεσμεύετε και να αποδεσμεύετε συνεχώς αντικείμενα στον σωρό
Για μαζικές εργασίες που παράγουν πολλά έγγραφα στη σειρά, το να δίνετε εμβέλεια σε ένα THotPDF ανά έγγραφο αξίζει το κόστος της δέσμευσης. Η κατάσταση δεν μεταφέρεται μεταξύ εγγράφων αν δεν υπάρχει αντικείμενο να τη μεταφέρει, και αυτή είναι μία κατηγορία διακοπτόμενων σφαλμάτων που δεν χρειάζεται ποτέ να αποσφαλματώσετε. Δεσμεύστε, παραγάγετε, διαγράψτε, επαναλάβετε
Μια ιδιότητα που εμφανίζεται σε αρκετά demo του HotPDF είναι το AutoLaunch, το οποίο ανοίγει το παραγόμενο αρχείο στο πρόγραμμα προβολής PDF του συστήματος αμέσως μετά το EndDoc. Είναι χρήσιμο όσο γράφετε το πρώτο προσχέδιο μιας διάταξης. Στην παραγωγή, παραλείψτε το: ανοίξτε ρητά τη διαδρομή εξόδου, επαληθεύστε ότι το αρχείο υπάρχει και έχει μη μηδενικό μέγεθος, καταγράψτε το αποτέλεσμα, και αφήστε τη ροή εργασίας που καλεί να αποφασίσει αν ένα πρόγραμμα προβολής έχει νόημα. Σε μια μαζική εργασία, το AutoLaunch ανοίγει ένα παράθυρο προβολής ανά έγγραφο και σε ορισμένα συστήματα θα μπλοκάρει τη διεργασία περιμένοντας να κλείσει το πρόγραμμα προβολής
Το στοιχείο THotPDF και όλες οι κλήσεις σχεδίασης που παρουσιάζονται εδώ αποτελούν μέρος του HotPDF Delphi Component για Delphi και C++Builder