Interactive form fields
A PDF does not have to be read-only. TTMSFNCPDFLib can place AcroForm fields on
a page — text edits, memos, password fields, check boxes, radio groups, combo
boxes, and list boxes — so the generated document can be filled in by the
recipient in any standard reader and returned. Use it for application forms,
expense claims, consent sheets, and anything where the alternative is printing,
filling by hand, and scanning back.
Form fields are the right tool when the recipient supplies the data. When the data is already known at generation time, draw it as ordinary text instead: it is simpler, it prints identically everywhere, and it cannot be changed by accident. A common middle ground is a pre-filled field marked read-only, covered below.
Note
FormFields is available where the library uses its built-in PDF writer: VCL,
FMX on Windows and Linux, and TMS WEB Core. On FMX for macOS, iOS, and Android
the library writes through the platform's native PDF engine and the
FormFields property is not declared at all, so code that uses it does not
compile for those targets. In a cross-platform FMX project, put the form-field
code under a conditional such as {$IF DEFINED(MSWINDOWS) or DEFINED(LINUX)}.
Adding fields
Add form fields via p.FormFields:
| Type | Method | Returns |
|---|---|---|
| Text edit | AddEdit |
ITMSFNCCustomPDFFormFieldEdit |
| Multiline text edit | AddMemo |
ITMSFNCCustomPDFFormFieldEdit |
| Password edit | AddPasswordEdit |
ITMSFNCCustomPDFFormFieldEdit |
| Combo box | AddComboBox |
ITMSFNCCustomPDFFormFieldComboBox |
| List box | AddListBox |
ITMSFNCCustomPDFFormFieldListBox |
| Check box | AddCheckBox |
— |
| Radio group | AddRadioGroup |
— |
| Radio button | AddRadioButton |
— |
Each field requires a unique name — it is the key the reader submits the value
under, so duplicates silently collapse into one value. All fields except radio
groups also require a TRectF position, in the same top-left page coordinates as
any drawing call. A field is added to the page that is current when the call is
made, so call NewPage first and add each page's fields before moving on to the
next page.
procedure TForm1.BuildMinimalForm(const AFileName: string);
var
p: TTMSFNCPDFLib;
begin
p := TTMSFNCPDFLib.Create;
try
p.Header := '';
p.Footer := '';
p.BeginDocument(AFileName);
try
{ Fields are added to the page that is current when the call is made,
so NewPage comes first. }
p.NewPage;
p.FormFields.AddEdit('Textfield1', RectF(10, 10, 210, 32), 'Default text', gtaLeading);
p.FormFields.AddCheckBox('Checkbox1', RectF(10, 50, 30, 70), False);
p.FormFields.AddComboBox('Combobox1', RectF(10, 90, 110, 110),
['item1', 'item2', 'item3'], 1);
finally
p.EndDocument;
end;
finally
p.Free;
end;
end;
void __fastcall TForm1::BuildMinimalForm(const String AFileName)
{
TTMSFNCPDFLib *p = new TTMSFNCPDFLib();
try
{
p->Header = "";
p->Footer = "";
p->BeginDocument(AFileName);
try
{
// Fields are added to the page that is current when the call is made,
// so NewPage comes first.
p->NewPage();
p->FormFields->AddEdit("Textfield1", RectF(10, 10, 210, 32), "Default text",
TTMSFNCGraphicsTextAlign::gtaLeading);
p->FormFields->AddCheckBox("Checkbox1", RectF(10, 50, 30, 70), false);
TTMSFNCPDFLibStringArray Items;
Items.Length = 3;
Items[0] = "item1";
Items[1] = "item2";
Items[2] = "item3";
p->FormFields->AddComboBox("Combobox1", RectF(10, 90, 110, 110), Items, 1);
}
__finally
{
p->EndDocument();
}
}
__finally
{
delete p;
}
}
Every Add method except AddRadioGroup also takes optional AReadOnly and
AHidden flags (see
Read-only and hidden fields). The text and choice
methods return an interface to the new field, through which you can change its
Text, Items, ItemIndex, Font, and other properties after it was added.
Text fields: edit, memo, and password
A text edit takes one line of input, a memo takes several, and a password edit
masks what is typed. AddEdit and AddMemo each have an overload with initial
text and one without; AddPasswordEdit has no initial-text overload. The
AHorizontalAlign parameter (gtaLeading by default) aligns the text inside the
field — gtaTrailing suits amounts and other numbers.
The returned ITMSFNCCustomPDFFormFieldEdit exposes Text, HorizontalAlign,
Font, and FontAutoSize, plus the FieldName, ReadOnly, and Hidden
properties every field has:
procedure TForm1.BuildAccountRequest(const AFileName: string);
var
p: TTMSFNCPDFLib;
Notes: ITMSFNCCustomPDFFormFieldEdit;
begin
p := TTMSFNCPDFLib.Create;
try
p.Header := '';
p.Footer := '';
p.BeginDocument(AFileName);
try
p.NewPage;
p.Graphics.Font.Size := 10;
p.Graphics.DrawText('User name', PointF(40, 44));
p.FormFields.AddEdit('UserName', RectF(150, 40, 400, 62));
{ Numbers read best right-aligned. }
p.Graphics.DrawText('Monthly budget', PointF(40, 76));
p.FormFields.AddEdit('Budget', RectF(150, 72, 260, 94), '0.00', gtaTrailing);
{ A memo is a multi-line edit: the recipient can type several lines. }
p.Graphics.DrawText('Motivation', PointF(40, 108));
Notes := p.FormFields.AddMemo('Motivation', RectF(150, 104, 400, 184),
'Describe why the account is needed.');
{ The returned interface changes the field after it was added. }
Notes.Font.Size := 9;
Notes.FontAutoSize := False;
{ A password field masks what the recipient types. It has no overload
for initial text. }
p.Graphics.DrawText('Temporary PIN', PointF(40, 200));
p.FormFields.AddPasswordEdit('TemporaryPIN', RectF(150, 196, 260, 218));
{ The field belongs to the document and is destroyed with it: release
the reference before the document is ended. }
Notes := nil;
finally
p.EndDocument;
end;
finally
p.Free;
end;
end;
void __fastcall TForm1::BuildAccountRequest(const String AFileName)
{
TTMSFNCPDFLib *p = new TTMSFNCPDFLib();
try
{
p->Header = "";
p->Footer = "";
p->BeginDocument(AFileName);
try
{
p->NewPage();
p->Graphics()->Font->Size = 10;
p->Graphics()->DrawText("User name", PointF(40, 44));
p->FormFields->AddEdit("UserName", RectF(150, 40, 400, 62));
// Numbers read best right-aligned.
p->Graphics()->DrawText("Monthly budget", PointF(40, 76));
p->FormFields->AddEdit("Budget", RectF(150, 72, 260, 94), "0.00",
TTMSFNCGraphicsTextAlign::gtaTrailing);
// A memo is a multi-line edit: the recipient can type several lines.
p->Graphics()->DrawText("Motivation", PointF(40, 108));
_di_ITMSFNCCustomPDFFormFieldEdit Notes = p->FormFields->AddMemo("Motivation",
RectF(150, 104, 400, 184), "Describe why the account is needed.");
// The returned interface changes the field after it was added.
Notes->Font->Size = 9;
Notes->FontAutoSize = false;
// A password field masks what the recipient types. It has no overload
// for initial text.
p->Graphics()->DrawText("Temporary PIN", PointF(40, 200));
p->FormFields->AddPasswordEdit("TemporaryPIN", RectF(150, 196, 260, 218));
// The field belongs to the document and is destroyed with it: release
// the reference before the document is ended.
Notes = nullptr;
}
__finally
{
p->EndDocument();
}
}
__finally
{
delete p;
}
}
Choice fields: combo box and list box
A combo box shows one value and drops down the rest; a list box shows several
options at once and suits a short list the recipient should see in full. Both take
their items either as a string array or as a TStrings, and an AItemIndex for
the preselected item (-1, the default, selects nothing). A combo box also takes
AEditable: when True, the recipient can type a value that is not in the list.
The TStrings overloads copy the items into the field, so a list you pass stays
yours to free. The returned interfaces expose Items, ItemIndex, and Font;
the combo box interface adds Editable and FontAutoSize.
procedure TForm1.BuildShippingForm(const AFileName: string);
var
p: TTMSFNCPDFLib;
Carriers: TStringList;
begin
{ The TStrings overloads copy the items, so the list stays yours to free. }
Carriers := TStringList.Create;
try
Carriers.Add('Standard post');
Carriers.Add('Express courier');
Carriers.Add('Pallet freight');
Carriers.Add('Collect in store');
p := TTMSFNCPDFLib.Create;
try
p.Header := '';
p.Footer := '';
p.BeginDocument(AFileName);
try
p.NewPage;
p.Graphics.Font.Size := 10;
{ A combo box shows one value and drops down the rest. AEditable = True
also lets the recipient type a country that is not in the list. }
p.Graphics.DrawText('Country', PointF(40, 44));
p.FormFields.AddComboBox('Country', RectF(150, 40, 330, 62),
['Belgium', 'France', 'Germany', 'Netherlands'], 0, True);
{ A list box shows several options at once. ItemIndex 1 preselects
"Express courier"; pass -1 to preselect nothing. }
p.Graphics.DrawText('Carrier', PointF(40, 80));
p.FormFields.AddListBox('Carrier', RectF(150, 76, 330, 146), Carriers, 1);
finally
p.EndDocument;
end;
finally
p.Free;
end;
finally
Carriers.Free;
end;
end;
void __fastcall TForm1::BuildShippingForm(const String AFileName)
{
// The TStrings overloads copy the items, so the list stays yours to free.
TStringList *Carriers = new TStringList();
try
{
Carriers->Add("Standard post");
Carriers->Add("Express courier");
Carriers->Add("Pallet freight");
Carriers->Add("Collect in store");
TTMSFNCPDFLib *p = new TTMSFNCPDFLib();
try
{
p->Header = "";
p->Footer = "";
p->BeginDocument(AFileName);
try
{
p->NewPage();
p->Graphics()->Font->Size = 10;
// A combo box shows one value and drops down the rest. AEditable = true
// also lets the recipient type a country that is not in the list.
TTMSFNCPDFLibStringArray Countries;
Countries.Length = 4;
Countries[0] = "Belgium";
Countries[1] = "France";
Countries[2] = "Germany";
Countries[3] = "Netherlands";
p->Graphics()->DrawText("Country", PointF(40, 44));
p->FormFields->AddComboBox("Country", RectF(150, 40, 330, 62),
Countries, 0, true);
// A list box shows several options at once. ItemIndex 1 preselects
// "Express courier"; pass -1 to preselect nothing.
p->Graphics()->DrawText("Carrier", PointF(40, 80));
p->FormFields->AddListBox("Carrier", RectF(150, 76, 330, 146), Carriers, 1);
}
__finally
{
p->EndDocument();
}
}
__finally
{
delete p;
}
}
__finally
{
delete Carriers;
}
}
Check boxes
AddCheckBox(AFieldName, ARect, AIsChecked) adds an independent on/off field; the
third parameter is its initial state. Check boxes return nothing, so everything
about them — name, position, state, and the read-only and hidden flags — is set in
the call itself. The check box has no caption, so draw its label next to the
rectangle, as in the sample in the next section.
Mutually exclusive radio buttons
A radio group is the one field type that does not take a rectangle, because it is
a logical container rather than a drawn control. Declare it with
AddRadioGroup(AFieldName, AGroupID), then add each button with
AddRadioButton(AFieldName, ARect, AGroupID, AIsChecked). The group id is what
ties the buttons to the group; each button still needs a field name of its own.
Buttons with the same group id are mutually exclusive; buttons that accidentally
end up with different group ids are not, which is the usual cause of "my radio
buttons can all be selected at once".
Mark exactly one button as checked. When more than one is marked, only the first one added counts as the group's value.
procedure TForm1.BuildPreferencesForm(const AFileName: string);
const
Sizes: array[0..2] of string = ('Small', 'Medium', 'Large');
var
p: TTMSFNCPDFLib;
I: Integer;
x: Single;
begin
p := TTMSFNCPDFLib.Create;
try
p.Header := '';
p.Footer := '';
p.BeginDocument(AFileName);
try
p.NewPage;
p.Graphics.Font.Size := 10;
{ Check boxes are independent: each has its own name and state. }
p.FormFields.AddCheckBox('Newsletter', RectF(40, 40, 56, 56), True);
p.Graphics.DrawText('Send me the newsletter', PointF(64, 42));
p.FormFields.AddCheckBox('Terms', RectF(40, 64, 56, 80), False);
p.Graphics.DrawText('I accept the terms of delivery', PointF(64, 66));
{ The group is declared once with its own field name and a group id;
each button joins it through that id and still needs a unique field
name of its own. Mark exactly one button as checked. }
p.Graphics.DrawText('Size', PointF(40, 102));
p.FormFields.AddRadioGroup('Size', 'SizeGroup');
for I := 0 to High(Sizes) do
begin
x := 100 + I * 90;
p.FormFields.AddRadioButton('Size' + Sizes[I], RectF(x, 100, x + 16, 116),
'SizeGroup', I = 1);
p.Graphics.DrawText(Sizes[I], PointF(x + 22, 102));
end;
finally
p.EndDocument;
end;
finally
p.Free;
end;
end;
void __fastcall TForm1::BuildPreferencesForm(const String AFileName)
{
const String Sizes[3] = {"Small", "Medium", "Large"};
TTMSFNCPDFLib *p = new TTMSFNCPDFLib();
try
{
p->Header = "";
p->Footer = "";
p->BeginDocument(AFileName);
try
{
p->NewPage();
p->Graphics()->Font->Size = 10;
// Check boxes are independent: each has its own name and state.
p->FormFields->AddCheckBox("Newsletter", RectF(40, 40, 56, 56), true);
p->Graphics()->DrawText("Send me the newsletter", PointF(64, 42));
p->FormFields->AddCheckBox("Terms", RectF(40, 64, 56, 80), false);
p->Graphics()->DrawText("I accept the terms of delivery", PointF(64, 66));
// The group is declared once with its own field name and a group id;
// each button joins it through that id and still needs a unique field
// name of its own. Mark exactly one button as checked.
p->Graphics()->DrawText("Size", PointF(40, 102));
p->FormFields->AddRadioGroup("Size", "SizeGroup");
for (int I = 0; I < 3; I++)
{
float x = 100 + I * 90;
p->FormFields->AddRadioButton("Size" + Sizes[I], RectF(x, 100, x + 16, 116),
"SizeGroup", I == 1);
p->Graphics()->DrawText(Sizes[I], PointF(x + 22, 102));
}
}
__finally
{
p->EndDocument();
}
}
__finally
{
delete p;
}
}
Read-only and hidden fields
AReadOnly := True shows the value but stops the recipient from changing it — the
natural choice for a claim number, a customer name, or any value your application
supplies and the returned form must keep. AHidden := True keeps the field out of
sight while it stays part of the form data, which is a way to carry an internal id
back with the filled-in form. Both flags are also available afterwards as the
ReadOnly and Hidden properties of a returned field interface.
procedure TForm1.BuildReturnForm(const AFileName, AReference: string; ACustomerId: Integer);
var
p: TTMSFNCPDFLib;
begin
p := TTMSFNCPDFLib.Create;
try
p.Header := '';
p.Footer := '';
p.BeginDocument(AFileName);
try
p.NewPage;
p.Graphics.Font.Size := 10;
{ Visible but locked: the value is part of the form data, and the
recipient cannot overwrite it. }
p.Graphics.DrawText('Return number', PointF(40, 44));
p.FormFields.AddEdit('ReturnNumber', RectF(150, 40, 300, 62), AReference,
gtaLeading, True);
{ Not shown at all, but still part of the form data - a way to carry an
internal id back with the filled-in form. }
p.FormFields.AddEdit('CustomerId', RectF(0, 0, 1, 1), IntToStr(ACustomerId),
gtaLeading, True, True);
p.Graphics.DrawText('Reason for return', PointF(40, 80));
p.FormFields.AddMemo('Reason', RectF(150, 76, 400, 146));
finally
p.EndDocument;
end;
finally
p.Free;
end;
end;
void __fastcall TForm1::BuildReturnForm(const String AFileName, const String AReference, int ACustomerId)
{
TTMSFNCPDFLib *p = new TTMSFNCPDFLib();
try
{
p->Header = "";
p->Footer = "";
p->BeginDocument(AFileName);
try
{
p->NewPage();
p->Graphics()->Font->Size = 10;
// Visible but locked: the value is part of the form data, and the
// recipient cannot overwrite it.
p->Graphics()->DrawText("Return number", PointF(40, 44));
p->FormFields->AddEdit("ReturnNumber", RectF(150, 40, 300, 62), AReference,
TTMSFNCGraphicsTextAlign::gtaLeading, true);
// Not shown at all, but still part of the form data - a way to carry an
// internal id back with the filled-in form.
p->FormFields->AddEdit("CustomerId", RectF(0, 0, 1, 1), IntToStr(ACustomerId),
TTMSFNCGraphicsTextAlign::gtaLeading, true, true);
p->Graphics()->DrawText("Reason for return", PointF(40, 80));
p->FormFields->AddMemo("Reason", RectF(150, 76, 400, 146));
}
__finally
{
p->EndDocument();
}
}
__finally
{
delete p;
}
}
Field fonts
FormFields.Font and FormFields.FontAutoSize are the defaults a field copies
when it is added. Set them before the first Add call: changing them afterwards
only affects fields added later. Text, combo box, and list box fields can then
override the font through the Font of their returned interface; check boxes and
radio buttons have no font.
| Property | Effect |
|---|---|
FontAutoSize |
When True, the reader scales the font to fit the field; available on FormFields (the default) and on edit and combo box fields |
IgnoreFonts |
When True, the field font settings are ignored and the reader uses its own default form font to draw the fields |
FontAutoSize is the practical answer to a field whose default text is clipped:
rather than shrinking the font for every field, let that one field size its own.
IgnoreFonts is for forms where the reader's standard form font is acceptable and
the fields do not need to match the document's typography; it applies to the form
fields only, and the rest of the document keeps its own fonts.
procedure TForm1.BuildFontedForm(const AFileName: string);
var
p: TTMSFNCPDFLib;
Total: ITMSFNCCustomPDFFormFieldEdit;
begin
p := TTMSFNCPDFLib.Create;
try
p.Header := '';
p.Footer := '';
p.BeginDocument(AFileName);
try
p.NewPage;
{ Every field copies these defaults at the moment it is added, so set
them before the first Add call. Changing them later only affects the
fields added afterwards. }
p.FormFields.Font.Name := 'Segoe UI';
p.FormFields.Font.Size := 10;
p.FormFields.Font.Color := gcDarkslategray;
p.FormFields.FontAutoSize := False;
p.Graphics.Font.Size := 10;
p.Graphics.DrawText('Description', PointF(40, 44));
p.FormFields.AddEdit('Description', RectF(150, 40, 450, 62));
{ One field with its own font: a larger, bold total. }
p.Graphics.DrawText('Total', PointF(40, 80));
Total := p.FormFields.AddEdit('Total', RectF(150, 74, 300, 100), '', gtaTrailing);
Total.Font.Size := 14;
Total.Font.Style := [TFontStyle.fsBold];
Total.Font.Color := gcBlack;
{ A narrow field whose default text would be clipped: let the reader
scale the font to the field instead. }
p.Graphics.DrawText('Code', PointF(40, 116));
p.FormFields.AddEdit('Code', RectF(150, 112, 210, 128), 'EU-2026-0142').FontAutoSize := True;
Total := nil;
finally
p.EndDocument;
end;
finally
p.Free;
end;
end;
void __fastcall TForm1::BuildFontedForm(const String AFileName)
{
TTMSFNCPDFLib *p = new TTMSFNCPDFLib();
try
{
p->Header = "";
p->Footer = "";
p->BeginDocument(AFileName);
try
{
p->NewPage();
// Every field copies these defaults at the moment it is added, so set
// them before the first Add call. Changing them later only affects the
// fields added afterwards.
p->FormFields->Font->Name = "Segoe UI";
p->FormFields->Font->Size = 10;
p->FormFields->Font->Color = gcDarkslategray;
p->FormFields->FontAutoSize = false;
p->Graphics()->Font->Size = 10;
p->Graphics()->DrawText("Description", PointF(40, 44));
p->FormFields->AddEdit("Description", RectF(150, 40, 450, 62));
// One field with its own font: a larger, bold total.
p->Graphics()->DrawText("Total", PointF(40, 80));
_di_ITMSFNCCustomPDFFormFieldEdit Total = p->FormFields->AddEdit("Total",
RectF(150, 74, 300, 100), "", TTMSFNCGraphicsTextAlign::gtaTrailing);
Total->Font->Size = 14;
Total->Font->Style = TFontStyles() << TFontStyle::fsBold;
Total->Font->Color = gcBlack;
// A narrow field whose default text would be clipped: let the reader
// scale the font to the field instead.
p->Graphics()->DrawText("Code", PointF(40, 116));
p->FormFields->AddEdit("Code", RectF(150, 112, 210, 128), "EU-2026-0142")->FontAutoSize = true;
Total = nullptr;
}
__finally
{
p->EndDocument();
}
}
__finally
{
delete p;
}
}
Labelling fields
Form fields carry no caption of their own. Draw the label as ordinary text next to the field rectangle, the same way you would label anything else on the page — see Text and fonts. Keep the label and the field rectangle in one place in the code so they cannot drift apart when the layout changes.
Common mistakes
- Adding fields before
NewPage. With no current page anAddcall does nothing; the text and choice methods then returnnil, so the next property access on the result fails. - Setting
FormFields.Fontafter the fields. Each field copies the default font when it is added; set the defaults first. - Keeping a field reference past
EndDocument. The returned interfaces point at fields owned by the document, which are released when the document is ended. Configure a field right after adding it and set your variable tonilbeforeEndDocument. - Moving a field through its
Rectproperty.Rectholds the field's position in the PDF's native coordinates (origin at the bottom-left), not the top-left page coordinates passed toAdd; position fields through theAddcall. - Reusing a field name. Names must be unique across the document; a duplicate makes two controls share one value.
- Radio buttons that are not mutually exclusive. They are only exclusive when they share one group id; also mark exactly one of them as checked.
- Expecting
FormFieldson FMX for macOS, iOS, or Android. The property does not exist there — see the note at the top. - Clipped default text. Set
FontAutoSize := Trueon the field rather than reducing the font for every field. - Expecting a caption. Fields are unlabelled; draw the text yourself.
Putting it together
A complete fillable page: shared field-font defaults set before the first field, drawn labels beside every control, a read-only claim number, text, amount, and memo fields, a combo box and a list box, a check box, and a radio group with two buttons.
procedure TForm1.BuildExpenseClaim(const AFileName, AClaimNumber: string);
var
p: TTMSFNCPDFLib;
begin
p := TTMSFNCPDFLib.Create;
try
p.Header := '';
p.Footer := '';
p.BeginDocument(AFileName);
try
p.NewPage;
{ Field font defaults first: each field copies them when it is added. }
p.FormFields.Font.Name := 'Segoe UI';
p.FormFields.Font.Size := 10;
p.FormFields.FontAutoSize := False;
p.Graphics.Font.Name := 'Segoe UI';
p.Graphics.Font.Size := 14;
p.Graphics.DrawText('Expense claim', PointF(40, 40));
p.Graphics.Font.Size := 10;
{ Fields carry no caption of their own - each label is ordinary drawn
text, kept on the line before the field it belongs to. }
p.Graphics.DrawText('Claim number', PointF(40, 76));
p.FormFields.AddEdit('ClaimNumber', RectF(150, 72, 300, 94), AClaimNumber,
gtaLeading, True);
p.Graphics.DrawText('Employee', PointF(40, 108));
p.FormFields.AddEdit('Employee', RectF(150, 104, 400, 126));
p.Graphics.DrawText('Amount', PointF(40, 140));
p.FormFields.AddEdit('Amount', RectF(150, 136, 260, 158), '0.00', gtaTrailing);
p.Graphics.DrawText('Cost centre', PointF(40, 172));
p.FormFields.AddComboBox('CostCentre', RectF(150, 168, 300, 190),
['Engineering', 'Sales', 'Support', 'Operations'], 0);
p.Graphics.DrawText('Category', PointF(40, 204));
p.FormFields.AddListBox('Category', RectF(150, 200, 300, 262),
['Travel', 'Meals', 'Lodging', 'Equipment'], -1);
p.Graphics.DrawText('Description', PointF(40, 276));
p.FormFields.AddMemo('Description', RectF(150, 272, 400, 332));
p.FormFields.AddCheckBox('ReceiptAttached', RectF(150, 344, 166, 360), False);
p.Graphics.DrawText('Receipt attached', PointF(172, 346));
{ One group, two buttons joined by the group id, one of them checked. }
p.Graphics.DrawText('Payment', PointF(40, 380));
p.FormFields.AddRadioGroup('Payment', 'PaymentGroup');
p.FormFields.AddRadioButton('PaymentTransfer', RectF(150, 378, 166, 394),
'PaymentGroup', True);
p.Graphics.DrawText('Bank transfer', PointF(172, 380));
p.FormFields.AddRadioButton('PaymentCash', RectF(280, 378, 296, 394),
'PaymentGroup', False);
p.Graphics.DrawText('Cash', PointF(302, 380));
finally
p.EndDocument;
end;
finally
p.Free;
end;
end;
void __fastcall TForm1::BuildExpenseClaim(const String AFileName, const String AClaimNumber)
{
TTMSFNCPDFLib *p = new TTMSFNCPDFLib();
try
{
p->Header = "";
p->Footer = "";
p->BeginDocument(AFileName);
try
{
p->NewPage();
// Field font defaults first: each field copies them when it is added.
p->FormFields->Font->Name = "Segoe UI";
p->FormFields->Font->Size = 10;
p->FormFields->FontAutoSize = false;
p->Graphics()->Font->Name = "Segoe UI";
p->Graphics()->Font->Size = 14;
p->Graphics()->DrawText("Expense claim", PointF(40, 40));
p->Graphics()->Font->Size = 10;
// Fields carry no caption of their own - each label is ordinary drawn
// text, kept on the line before the field it belongs to.
p->Graphics()->DrawText("Claim number", PointF(40, 76));
p->FormFields->AddEdit("ClaimNumber", RectF(150, 72, 300, 94), AClaimNumber,
TTMSFNCGraphicsTextAlign::gtaLeading, true);
p->Graphics()->DrawText("Employee", PointF(40, 108));
p->FormFields->AddEdit("Employee", RectF(150, 104, 400, 126));
p->Graphics()->DrawText("Amount", PointF(40, 140));
p->FormFields->AddEdit("Amount", RectF(150, 136, 260, 158), "0.00",
TTMSFNCGraphicsTextAlign::gtaTrailing);
TTMSFNCPDFLibStringArray CostCentres;
CostCentres.Length = 4;
CostCentres[0] = "Engineering";
CostCentres[1] = "Sales";
CostCentres[2] = "Support";
CostCentres[3] = "Operations";
p->Graphics()->DrawText("Cost centre", PointF(40, 172));
p->FormFields->AddComboBox("CostCentre", RectF(150, 168, 300, 190), CostCentres, 0);
TTMSFNCPDFLibStringArray Categories;
Categories.Length = 4;
Categories[0] = "Travel";
Categories[1] = "Meals";
Categories[2] = "Lodging";
Categories[3] = "Equipment";
p->Graphics()->DrawText("Category", PointF(40, 204));
p->FormFields->AddListBox("Category", RectF(150, 200, 300, 262), Categories, -1);
p->Graphics()->DrawText("Description", PointF(40, 276));
p->FormFields->AddMemo("Description", RectF(150, 272, 400, 332));
p->FormFields->AddCheckBox("ReceiptAttached", RectF(150, 344, 166, 360), false);
p->Graphics()->DrawText("Receipt attached", PointF(172, 346));
// One group, two buttons joined by the group id, one of them checked.
p->Graphics()->DrawText("Payment", PointF(40, 380));
p->FormFields->AddRadioGroup("Payment", "PaymentGroup");
p->FormFields->AddRadioButton("PaymentTransfer", RectF(150, 378, 166, 394),
"PaymentGroup", true);
p->Graphics()->DrawText("Bank transfer", PointF(172, 380));
p->FormFields->AddRadioButton("PaymentCash", RectF(280, 378, 296, 394),
"PaymentGroup", false);
p->Graphics()->DrawText("Cash", PointF(302, 380));
}
__finally
{
p->EndDocument();
}
}
__finally
{
delete p;
}
}