Artigo técnico

Criar e liberar dinamicamente um componente HotPDF no C++Builder

· Programação PDF

A maioria dos exemplos do HotPDF coloca um componente em um form em tempo de design. Isso é conveniente para demos, mas código de produção às vezes precisa criar o componente PDF apenas para uma operação de exportação específica. A criação dinâmica é útil em módulos de serviço, auxiliares de relatório, jobs em lote e forms em que o componente não deve existir durante toda a vida do form.

O padrão básico do C++Builder é alocar uma instância THotPDF, configurar o arquivo de saída e as opções do documento, gerar o PDF e liberar o componente quando a operação terminar. O exemplo abaixo mostra o fluxo mínimo dentro de um handler de botão.

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

Ownership e limpeza

O construtor recebe this como owner, então o form pode limpar o componente se ele continuar vivo. Neste exemplo curto, o objeto também é liberado explicitamente após EndDoc. Em código real, mantenha o caminho de limpeza seguro contra exceções: se a geração de PDF puder falhar, envolva o trabalho em um bloco try/__finally ou use um pequeno helper RAII para que Free() ainda seja executado.

Não chame métodos no componente depois de Free() e evite armazenar o ponteiro em um escopo mais amplo, a menos que outra parte do form realmente possua o ciclo de vida do componente. Uma variável local geralmente é a escolha mais simples para exportações PDF pontuais.

Notas de configuração do projeto

O projeto deve conseguir encontrar os headers, bibliotecas e packages de design/runtime do HotPDF. Adicione o diretório include do HotPDF ao path de include C++ e o diretório da biblioteca ao path de busca do linker. Se o projeto vincula HPDFDoc, mantenha os nomes de package e unit inalterados para que o C++Builder resolva os headers gerados.

Antes de distribuir

  • Use um path de saída absoluto ou validado ao gerar arquivos fora de uma pasta de demonstração.
  • Chame BeginDoc e EndDoc em pares equilibrados.
  • Abra o PDF gerado em pelo menos um visualizador externo, não apenas com AutoLaunch.
  • Registre erros de geração para que o suporte consiga distinguir problemas de path, permissão, fonte e renderização PDF.

Estrutura segura contra exceções

O exemplo mantém o código compacto, mas uma rotina real de exportação deve tratar exceções entre a alocação e a limpeza. A geração de PDF pode falhar porque a pasta de saída é somente leitura, uma fonte não pode ser resolvida, um stream é fechado cedo demais ou dados do usuário contêm um valor inesperado. O caminho de limpeza não deve depender do sucesso de cada chamada de desenho.

Uma abordagem prática é criar o componente imediatamente antes da exportação e liberá-lo em um bloco de limpeza garantido. Isso mantém a vida do componente vinculada a um único job PDF. Se a aplicação gera muitos documentos em sequência, esse padrão também reduz a chance de estado de um documento vazar para o próximo.

Componentes em tempo de design versus runtime

Um componente em tempo de design é mais fácil quando um form possui um fluxo de exportação previsível. Um componente em runtime é melhor quando a aplicação precisa de vários exportadores temporários, escolhe configurações dinamicamente ou executa código de exportação a partir de uma classe auxiliar em vez de um form. As chamadas de API são as mesmas; a diferença é apenas quem possui o objeto e por quanto tempo ele vive.

Para código em estilo servidor ou lote, evite depender de AutoLaunch. Gere o arquivo, verifique se ele existe, registre o path de saída e deixe o fluxo chamador decidir se um visualizador deve ser aberto.