Artículo técnico

Crear y liberar dinámicamente un componente HotPDF en C++Builder

· Programación PDF

La mayoría de los ejemplos de HotPDF colocan un componente en un formulario en tiempo de diseño. Es cómodo para demostraciones, pero el código de producción a veces necesita crear el componente PDF solo para una operación de exportación concreta. La creación dinámica es útil en módulos de servicio, ayudantes de informes, trabajos por lotes y formularios donde el componente no debe vivir durante toda la vida del formulario.

El patrón básico de C++Builder consiste en asignar una instancia de THotPDF, configurar el archivo de salida y las opciones del documento, generar el PDF y liberar el componente cuando termina la operación. El ejemplo siguiente muestra el flujo mínimo dentro de un manejador de botón.

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();
}

Propiedad y limpieza

El constructor recibe this como propietario, por lo que el formulario puede limpiar el componente si sigue vivo. En este ejemplo corto el objeto también se libera explícitamente después de EndDoc. En código real, mantén la ruta de limpieza segura ante excepciones: si la generación de PDF puede fallar, envuelve el trabajo en un bloque try/__finally o usa un pequeño ayudante RAII para que Free() se ejecute igualmente.

No llames métodos del componente después de Free() y evita guardar el puntero en un ámbito más amplio salvo que otra parte del formulario posea realmente el ciclo de vida del componente. Una variable local suele ser la opción más simple para exportaciones PDF de una sola ejecución.

Notas de configuración del proyecto

El proyecto debe poder encontrar los encabezados, bibliotecas y paquetes de diseño/ejecución de HotPDF. Añade el directorio include de HotPDF a la ruta de include de C++ y el directorio de bibliotecas a la ruta de búsqueda del enlazador. Si el proyecto enlaza HPDFDoc, conserva sin cambios los nombres de paquete y unidad para que C++Builder resuelva los encabezados generados.

Antes de publicar

  • Usa una ruta de salida absoluta o validada al generar archivos fuera de una carpeta de demostración.
  • Llama BeginDoc y EndDoc en pares equilibrados.
  • Abre el PDF generado en al menos un visor externo, no solo con AutoLaunch.
  • Registra los errores de generación para que soporte pueda distinguir problemas de ruta, permisos, fuentes y renderizado PDF.

Estructura segura ante excepciones

El ejemplo mantiene el código compacto, pero una rutina de exportación real debe manejar excepciones entre la asignación y la limpieza. La generación de PDF puede fallar porque la carpeta de salida es de solo lectura, una fuente no se resuelve, un stream se cierra demasiado pronto o los datos del usuario contienen un valor inesperado. La ruta de limpieza no debe depender del éxito de cada llamada de dibujo.

Un enfoque práctico es crear el componente justo antes de la exportación y liberarlo en un bloque de limpieza garantizado. Así la vida del componente queda ligada a un solo trabajo PDF. Si la aplicación genera muchos documentos en secuencia, este patrón también reduce la posibilidad de que estado de un documento se filtre al siguiente.

Componentes de diseño frente a componentes en tiempo de ejecución

Un componente en tiempo de diseño es más fácil cuando un formulario posee un flujo de exportación predecible. Un componente en tiempo de ejecución es mejor cuando la aplicación necesita varios exportadores temporales, elige ajustes dinámicamente o ejecuta código de exportación desde una clase auxiliar en vez de desde un formulario. Las llamadas de API son las mismas; la diferencia es solo quién posee el objeto y cuánto tiempo vive.

Para código de servidor o por lotes, evita depender de AutoLaunch. Genera el archivo, comprueba que existe, registra la ruta de salida y deja que el flujo llamador decida si debe abrirse un visor.