很多 HotPDF 示例会在设计期把组件放到窗体上。这样写演示很方便,但生产代码有时只需要在某次导出操作中临时创建 PDF 组件。动态创建适合服务模块、报表辅助类、批处理任务,以及组件不应跟随窗体整个生命周期存在的场景。
基本模式是分配一个 THotPDF 实例,设置输出文件和文档选项,生成 PDF,然后在操作结束时释放组件。下面的示例展示了按钮事件中的最小流程。
|
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(); } |
所有权和清理
构造函数传入 this 作为 owner,因此如果组件仍然存活,窗体可以负责清理。在这个短示例中,对象也会在 EndDoc 之后显式释放。实际代码应让清理路径具备异常安全性:如果 PDF 生成可能失败,请用 try/__finally 或小型 RAII 辅助对象确保 Free() 仍会执行。
调用 Free() 后不要再访问组件。除非窗体其他部分确实需要管理组件生命周期,否则不要把指针保存到更大的作用域里。对于一次性 PDF 导出,局部变量通常最简单。
项目配置注意事项
项目必须能找到 HotPDF 的头文件、库文件以及设计期或运行期包。把 HotPDF include 目录加入 C++ include path,把库目录加入 linker search path。如果项目链接 HPDFDoc,保持包名和单元名不变,让 C++Builder 能解析生成的头文件。
异常安全结构
示例代码保持简洁,但真实导出例程要处理分配和清理之间的异常。PDF 生成可能因为输出目录只读、字体无法解析、流提前关闭或用户数据异常而失败。清理路径不应依赖每个绘制调用都成功。
一个实用做法是在导出前立即创建组件,并在保证执行的清理块中释放。这样组件生命周期只绑定到一次 PDF 任务。如果应用连续生成多份文档,也能降低一个文档状态泄漏到下一个文档的风险。
设计期组件与运行期组件
如果一个窗体拥有一个固定导出流程,设计期组件更简单。如果应用需要多个临时导出器、动态选择设置,或从辅助类运行导出代码,运行期组件更合适。API 调用相同,区别只在于谁拥有对象以及对象存活多久。
- 为输出文件使用绝对路径或经过验证的路径。
- 保持
BeginDoc和EndDoc成对出现。 - 不要在批处理或服务式代码中依赖
AutoLaunch。 - 记录生成错误,便于区分路径、权限、字体和渲染问题。