HotPDF は Delphi/C++Builder アプリケーション向けのネイティブ VCL PDF ライブラリです。外部 PDF ランタイムを配置せずに、PDF 作成、編集、フォーム、注釈、暗号化、デジタル署名、Unicode フォント、標準対応出力、プリフライトレポートを扱えます。
この記事は developers replacing hand-edited PDF forms with deterministic Delphi form generation 向けです。AcroForm fields and action logic を単なるコンポーネント呼び出しではなく、本番向けのドキュメントエンジニアリングとして扱います。
実務上のリスクは field widgets can look correct while shared names, export values, JavaScript actions, tab order, or flattening rules break the receiving workflow です。そのため、明確な契約、観測可能な診断、実際の顧客ファイルに近い回帰サンプルが必要です。
アーキテクチャ上の判断
Treat the field map as an application contract. field naming rules for repeated widgets and grouped business values / allowed trigger actions, submit targets, and viewer-side script policy
- field naming rules for repeated widgets and grouped business values
- allowed trigger actions, submit targets, and viewer-side script policy
- required flags, default values, calculation order, and validation messages
- whether the output remains interactive or is flattened for archive delivery
実装フロー
Build the form layer before assigning values. The order below keeps the workflow reviewable for Delphi and C++Builder teams.
- inventory the template fields and normalize names before binding application data
- apply values only after the allowed action profile has been selected
- refresh widget appearances with the same font and color policy used at design time
- validate exported values and tab order in the same viewer family used by customers
- flatten only after all required-field and calculation checks have passed
検証エビデンス
Evidence that proves the form is usable. Keep these fields with the output or support record.
- field name, widget bounds, page number, required state, and exported value
- action type, trigger event, destination, and whether the profile allowed it
- appearance stream status, font fallback decision, and calculated-field result
- remaining interactive fields after flattening and warnings for unsupported actions
Appearance streams, actions, and flattening order
A production form workflow separates field creation, value assignment, appearance refresh, action binding, and final flattening. Keeping those phases visible makes it possible to explain why a required field failed or why a submit action was suppressed.
Decision table for AcroForm fields and action logic
A decision table keeps product ownership visible when the same workflow is reused by a desktop tool, service job, and support utility.
| Decision | Engineering reason | Evidence |
|---|---|---|
| field naming rules for repeated widgets and grouped business values | inventory the template fields and normalize names before binding application data | field name, widget bounds, page number, required state, and exported value |
| allowed trigger actions, submit targets, and viewer-side script policy | apply values only after the allowed action profile has been selected | action type, trigger event, destination, and whether the profile allowed it |
| required flags, default values, calculation order, and validation messages | refresh widget appearances with the same font and color policy used at design time | appearance stream status, font fallback decision, and calculated-field result |
AcroForm fields and action logic に関する技術レビューの注意点
これらのレビュー項目を使って、機能がデモ段階を超え、リリース、サポート、顧客エスカレーションの場で説明できることを確認します
- 判断: field naming rules for repeated widgets and grouped business values. 実装上の焦点: apply values only after the allowed action profile has been selected. 受け入れ証拠: appearance stream status, font fallback decision, and calculated-field result. 回帰の引き金: flattening before validation can permanently hide incomplete or inconsistent data
- 判断: allowed trigger actions, submit targets, and viewer-side script policy. 実装上の焦点: refresh widget appearances with the same font and color policy used at design time. 受け入れ証拠: remaining interactive fields after flattening and warnings for unsupported actions. 回帰の引き金: checkbox captions do not always match the export values consumed by external systems
境界ケース
- checkbox captions do not always match the export values consumed by external systems
- identically named fields may intentionally share one value across several pages
- viewer security settings can block actions that worked during development
- flattening before validation can permanently hide incomplete or inconsistent data
Delphi / C++Builder の補足
HotPDF Component should sit behind a small service boundary that receives files, streams, profiles, and credentials, then returns output paths, warnings, metrics, and validation status. 重要な用語には AcroForm, widget, field action, appearance stream, submit action, flattening.
Delphi コード例
次の Delphi スケッチは、このテーマに対する実用的なサービス境界を示します。ポリシー確認、ログ記録、検証を製品呼び出しの狭い部分の外側に置くと、ワークフローをテストしやすくなります。
procedure BuildAcroFormPackage(const OutputFile: string; const Profile: TFormProfile);
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := OutputFile;
Pdf.BeginDoc;
AddCustomerFields(Pdf, Profile);
WireSubmitActions(Pdf, Profile.ActionMap);
ValidateRequiredFields(Profile.RequiredFields);
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
本番チェックリスト
- ワークフローは、空のファイル、通常の顧客ファイル、最悪ケースのファイルで実行します
- 生成された PDF は、対象のビューアー、検証ツール、プリンター、または downstream アプリケーションで開きます
- 製品バージョン、プロファイルバージョン、入力ハッシュ、出力パス、経過時間、警告数を記録します
- パスワード、証明書、一時ファイル、顧客データは明確な保持ルールの下で管理します
- 顧客ファイルが新しい境界ケースを示したら、回帰用ドキュメントを追加します
製品ドキュメント
追加のコード例
// Open a help page in the system browser
Pdf.CurrentPage.AddPushButtonWithAction('btnHelp', 'Help',
'https://www.example.com/claims-help', Rect(320, 700, 420, 730), baURI);
// Run viewer-side JavaScript
Pdf.CurrentPage.AddPushButtonWithAction('btnRecalc', 'Recalculate',
'app.alert("Totals updated.");', Rect(320, 660, 420, 690), baJavaScript);
// Submit as XFDF and keep empty fields in the payload
Pdf.CurrentPage.AddPushButtonWithSubmitAction('btnSubmit', 'Submit claim',
'https://api.example.com/claims', Rect(320, 620, 420, 650),
[sffXFDF, sffIncludeNoValueFields]);// Reject committed values that are not plausible email addresses
Pdf.AttachFieldKeyStrokeAction('applicant.email',
'if (event.willCommit && !/^[\w.-]+@[\w.-]+\.\w+$/.test(event.value)) event.rc = false;');
// Display US phone numbers as (NNN) NNN-NNNN
Pdf.AttachFieldFormatAction('applicant.phone',
'event.value = event.value.replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3");');
// Refuse applicants under 18 at commit time
Pdf.AttachFieldValidateAction('applicant.age',
'if (parseInt(event.value) < 18) event.rc = false;');