إن إسقاط THotPDF على نموذج وقت التصميم مناسب لنموذج أولي سريع، لكنه يربط المكون بعمر النموذج، وهذا ليس ما يريده كود الإنتاج غالبا. مولد تقارير يعمل مرة عند كل نقرة زر، أو خيط خدمة يجري تصدير الدفعات ليلا، أو فئة مساعدة لا تملك نموذجا أصلا: في كل هذه الحالات تريد أن يوجد المكون طوال مدة مهمة PDF واحدة فقط ثم يختفي. هذا يعني التخصيص وقت التشغيل، ويغيّر شيئين يجب فهمهما قبل كتابة السطر الأول: من يملك الكائن، وكيف يجري التنظيف عند حدوث خطأ
دلالات Owner في VCL
يأخذ كل منشئ مكون VCL معاملا باسم Owner من النوع TComponent*. تمرير this، أي النموذج، يسجل الكائن الجديد في قائمة المكونات المملوكة للنموذج، فإذا دُمّر النموذج بينما كان المكون ما يزال حيا، تقوم VCL بتحريره تلقائيا. أما تمرير nullptr فيعني عدم وجود مالك: أنت تتحمل وحدك مسؤولية المؤشر، ولن ينظفه أي شيء إذا أدى استثناء إلى فك المكدس قبل delete الصريح
في عملية تصدير لمرة واحدة تنتهي داخل دالة واحدة، يصلح أي الخيارين، لكن لكل منهما نمط فشل مختلف. مع this كمالك، لا يمكن أن يحدث تسرب ما دام النموذج سيُغلق في النهاية؛ ومع nullptr يجب أن يصل المؤشر إلى كتلة __finally. عمليا، يكون نمط nullptr مع __finally أنظف قليلا للكائنات قصيرة العمر لأنه يجعل حد العمر مرئيا من النظرة الأولى، ويتجنب تراكم كائنات مملوكة في النموذج كانت مقصودة على أنها مؤقتة
بنية آمنة مع الاستثناءات
قد يفشل توليد PDF لأسباب لا علاقة لها بواجهة البرمجة: مجلد الإخراج للقراءة فقط، أو ملف خط مفقود، أو تفريغ مبكر لتيار بيانات، أو وصول بيانات يوفرها المستدعي إلى حد الطول. أيا كان السبب، يجب أن يعمل مسار التنظيف. الطريقة القياسية في 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;
}
}
ثمة أمور قليلة في ذلك المقطع تستحق التنبيه. المالك هو nullptr، وهذا يجعل العمر واضحا. يتم ضبط Compression وFontEmbedding قبل BeginDoc، فهما خياران على مستوى المستند يثبتهما HotPDF عند فتح المستند، وأي إسناد بعد ذلك لا تأثير له. يأخذ TextOut الإحداثيات بوحدة النقاط المقاسة من الزاوية السفلية اليسرى للصفحة، مع زيادة محور Y إلى أعلى؛ والزوج 72، 720 يضع النص قرب أعلى اليسار في صفحة بحجم letter مع هامش أيسر بوصة واحدة. أما delete Pdf داخل كتلة __finally فيعمل سواء ألقى BeginDoc أو الرسم أو EndDoc استثناء أم لا
تجنب استدعاء أي طريقة على Pdf بعد delete. إذا كان المؤشر مخزنا في متغير عضو، فاضبطه إلى nullptr مباشرة بعد الحذف حتى ينتج عن أي وصول لاحق غير مقصود تعطل واضح بدلا من تلف صامت
إعداد المشروع
يعثر C++Builder على THotPDF عبر مزيج من مسارات include ومسارات المكتبات وتعليمة pragma. يوجد الرأس المولد بجوار HPDFDoc.pas في مجلد مصادر HotPDF؛ أضف ذلك المجلد إلى Project > Options > C++ Compiler > Include path. تشير التعليمة #pragma link "HPDFDoc" إلى الرابط ليضم الوحدة المترجمة من دون إدراجها يدويا في ملف المشروع. إذا كنت تستخدم حزمة وقت التشغيل بدلا من الربط الساكن، فقم أولا بتثبيت حزمتَي التصميم ووقت التشغيل لـ HotPDF؛ ولا تزال هذه التعليمة صالحة
احتفظ باسم الوحدة HPDFDoc كما هو من دون تغيير. يستخلص C++Builder اسم الرأس من اسم وحدة Pascal، لذلك فإن إعادة تسمية الملف أو استخدام اسم مستعار للمسار داخل pragma يكسر عملية البحث بصمت
تحديد النطاق ومهام متعددة المستندات
عندما يكون هناك تصدير واحد يطلقه إجراء المستخدم، فإن متغيرا محليا ضمن نطاق معالج الزر هو الجواب الصحيح: يُنشأ داخل إطار استدعاء واحد، ويُستخدم ثم يُدمّر داخله، وتكون النية واضحة لأي شخص يقرأ الكود لاحقا. أما البديل وقت التصميم فيصبح مبررا عندما يقود النموذج نفسه تدفق عمل مستمرا، مثل لوحة معاينة طباعة تعيد بناء المستند كلما غيّر المستخدم إعدادا؛ في تلك الحالة، يكون إبقاء المكون حيا واستدعاء BeginDoc/EndDoc بشكل متكرر أقل إرباكا من التخصيص والتحرير المتكرر لعناصر heap
في مهام الدفعات التي تنتج مستندات كثيرة بالتتابع، يكون تخصيص THotPDF واحد لكل مستند جديرا بكلفة التخصيص. لا تنتقل الحالة بين المستندات إذا لم يوجد كائن يحملها، وهذه فئة من الأخطاء المتقطعة التي لن تضطر إلى تتبعها أبدا. خصص، أنشئ، حرر، وكرر
إحدى الخصائص التي تظهر في عدة عروض HotPDF هي AutoLaunch، وهي تفتح الملف الناتج في عارض PDF الافتراضي للنظام مباشرة بعد EndDoc. وهي مفيدة أثناء كتابة المسودة الأولى لتخطيط الصفحة. في الإنتاج، تجاهلها: افتح مسار الإخراج صراحة، وتحقق من وجود الملف وأن حجمه غير صفري، وسجل النتيجة، ودع سير العمل المستدعي يقرر ما إذا كان العارض ذا صلة. في مهمة دفعية، يفتح AutoLaunch نافذة عارض واحدة لكل مستند وسيحجب العملية على بعض الأنظمة حتى يغلق العارض
يعد THotPDF وجميع استدعاءات الرسم المعروضة هنا جزءا من مكون HotPDF لـ Delphi وC++Builder