FlexCel Studio for VCL / FireMonkey
This skill helps write Delphi (VCL, FMX, Lazarus/LCL, Linux/SKIA) and C++Builder code that uses FlexCel — the TMS Software library for working with Excel .xlsx / .xls files, exporting to PDF/HTML/images, and generating data-driven reports from templates.
When to use this skill
Activate whenever the user wants to, from Pascal/Delphi/C++Builder code:
- Read an Excel file (
.xlsx or .xls) — cell values, formulas, formatting.
- Create or modify an Excel file programmatically.
- Generate reports by merging data into Excel templates.
- Export an Excel file to PDF, HTML, SVG, or images.
- Autofit rows/columns, render sheets, or measure cells.
- Target VCL, FireMonkey (desktop & mobile), Lazarus, or Delphi Linux.
FlexCel does not require Excel or any Office installation on the target machine. It has no OLE/COM dependency.
Two ways to create Excel files — pick one
Before writing code, decide which API fits the task:
| If the user wants to… |
Use |
Why |
| Read existing files, or build files cell-by-cell in code |
TXlsFile API (FlexCel.XlsAdapter) |
Full programmatic control; no designer required. |
| Produce the same report repeatedly from changing data, with a styled layout |
TFlexCelReport + Excel template (FlexCel.Report) |
Non-programmers can edit the template in Excel; code just provides data. |
When the user says "generate a report with company logo / nice formatting / many rows from a database", prefer Reports. When they say "read this file and extract values" or "create an Excel file with these calculations", prefer the API.
You can combine both: run a report to produce an in-memory TXlsFile, then manipulate it with the API, then export to PDF.
Quick-start recipes
All examples assume VCL. For FireMonkey replace FlexCel.VCLSupport with FlexCel.FMXSupport; for Lazarus use FlexCel.LCLSupport; for Delphi Linux use FlexCel.SKIASupport. The platform support unit goes in the main program (.dpr) uses clause only, not every unit.
Recipe 1 — Create an Excel file
uses
System.IOUtils,
FlexCel.Core, FlexCel.XlsAdapter;
procedure CreateExcelFile;
var
xls: TXlsFile;
begin
// Start an empty workbook with 1 sheet and Excel-2019 default formatting.
xls := TXlsFile.Create(1, TExcelFileFormat.v2019, true);
try
xls.SetCellValue(1, 1, 'Hello from FlexCel!'); // A1 text
xls.SetCellValue(2, 1, 7); // A2 number
xls.SetCellValue(3, 1, 11.3); // A3 number
xls.SetCellValue(4, 1, TFormula.Create('=Sum(A2:A3)')); // A4 formula
xls.Save(TPath.Combine(TPath.GetDocumentsPath, 'test.xlsx'));
finally
xls.Free;
end;
end;
Key points:
- All row/column/sheet indices are 1-based.
(1, 1) is cell A1. (XF format indices are the single exception — they're 0-based.)
- File format is inferred from the extension (
.xlsx → OOXML, .xls → BIFF8).
TXlsFile is a plain class, not a component — you create it in code and must Free it.
Recipe 2 — Read an Excel file
uses
System.IOUtils,
FlexCel.Core, FlexCel.XlsAdapter;
procedure ReadExcelFile(const aMemo: TMemo);
var
xls: TXlsFile;
row, colIndex, XF: integer;
cell: TCellValue;
addr: TCellAddress;
s: string;
begin
xls := TXlsFile.Create(TPath.Combine(TPath.GetDocumentsPath, 'test.xlsx'));
try
xls.ActiveSheetByName := 'Sheet1'; // or loop xls.ActiveSheet from 1 to xls.SheetCount
for row := 1 to xls.RowCount do
begin
// Use ColCountInRow, NOT ColCount — much faster. See performance guide.
for colIndex := 1 to xls.ColCountInRow(row) do
begin
XF := -1;
cell := xls.GetCellValueIndexed(row, colIndex, XF);
addr := TCellAddress.Create(row, xls.ColFromIndex(row, colIndex));
s := 'Cell ' + addr.CellRef + ' ';
if cell.IsEmpty then s := s + 'is empty.'
else if cell.IsString then s := s + 'string: ' + cell.ToString
else if cell.IsNumber then s := s + 'number: ' + FloatToStr(cell.AsNumber)
else if cell.IsBoolean then s := s + 'bool: ' + BoolToStr(cell.AsBoolean)
else if cell.IsError then s := s + 'error: ' + cell.ToString
else if cell.IsFormula then s := s + 'formula: ' + cell.AsFormula.Text;
aMemo.Lines.Add(s);
end;
end;
finally
xls.Free;
end;
end;
Key points:
- Iterate with
ColCountInRow(row) combined with GetCellValueIndexed + ColFromIndex — this skips empty cells and is dramatically faster than a dense 1..ColCount loop.
TCellValue is a discriminated-union record. Test with IsEmpty / IsString / IsNumber / IsBoolean / IsError / IsFormula, then extract with ToString / AsNumber / AsBoolean / AsFormula.
- Excel dates are stored as numbers; detect them via the cell's format, not the value type.
Recipe 3 — Export Excel to PDF
uses
FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Render;
procedure XlsxToPdf(const Source, Dest: string);
var
xls: TXlsFile;
pdf: TFlexCelPdfExport;
begin
xls := TXlsFile.Create(Source);
try
pdf := TFlexCelPdfExport.Create(xls);
try
pdf.Export(Dest); // one PDF covering all visible sheets
finally
pdf.Free;
end;
finally
xls.Free;
end;
end;
PDF export needs FlexCel.Render plus the platform-support unit in the main .dpr (the renderer uses the graphics engine for font measurement). For PDF/A, digital signatures, font embedding tuning, or multi-sheet bookmarks see references/pdf-html-export.md.
Recipe 4 — Run a report from a template
Assume an Excel template invoice-template.xlsx already exists, with tags like <#Customers.Name> inside a named range __Customers__ spanning the repeating row(s).
uses
FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Report;
procedure RunReport(Customers: TDataSet);
var
report: TFlexCelReport;
begin
report := TFlexCelReport.Create(true); // true = case-insensitive tags
try
report.AddTable('Customers', Customers, TDisposeMode.DoNotDispose);
report.SetValue('ReportDate', Now);
report.SetValue('CompanyName', 'Acme Corp');
report.Run('invoice-template.xlsx', 'invoice-output.xlsx');
finally
report.Free;
end;
end;
To write the output straight to PDF, run the report into a TXlsFile and pipe it through TFlexCelPdfExport:
out := TXlsFile.Create;
try
report.Run('template.xlsx', out);
pdf := TFlexCelPdfExport.Create(out);
try pdf.Export('report.pdf'); finally pdf.Free end;
finally
out.Free;
end;
For the full tag language and template-design conventions see references/reports-cheatsheet.md.
Unit reference (what to put in uses)
Always include FlexCel.Core in every unit that touches FlexCel types. Then add, per task:
| Task |
Additional units |
Platform graphics (main .dpr only) |
FlexCel.VCLSupport / FlexCel.FMXSupport / FlexCel.LCLSupport / FlexCel.SKIASupport |
| Read / write xls/xlsx |
FlexCel.XlsAdapter |
| PDF / HTML / image export, autofitting |
FlexCel.Render |
| Low-level PDF access (sign, PDF/A options, standalone PDF) |
FlexCel.Pdf |
| Template-based reports |
FlexCel.Report |
Critical gotchas (read this every time)
- 1-based indexing for rows, columns, sheets.
SetCellValue(1, 1, ...) writes to A1. (XF format indices are 0-based.)
- Always
Free TXlsFile, TFlexCelReport, TFlexCelPdfExport, etc. They're plain classes, not components. Use try..finally.
- Don't iterate with
ColCount — it scans the whole sheet. Use ColCountInRow(row) + GetCellValueIndexed + ColFromIndex.
- Platform support unit belongs in the
.dpr only, not in every unit — it has no published types.
- Dates are numbers.
GetCellValue returns the serial date; check the cell's number format to know it's a date.
- Measurement units in Excel are unusual — column widths are in 1/256 of a character, row heights in 1/20 of a point, etc. See the "Understanding Excel measurement units" tip in the docs before fiddling with widths/heights.
- Use APIMate. When the user asks "how do I make a cell blue / add an autofilter / create a pivot table", the canonical answer is: do it in Excel, open the file in APIMate (ships with FlexCel), and copy the generated Delphi/C++ code. APIMate is the recommended way to discover API calls for anything Excel-specific. Mention this to the user.
When to consult the references
Load a reference file only when the task actually needs it — keeps your context lean.
references/api-cheatsheet.md — deeper TXlsFile usage: formatting, fonts, colors, merging, row/column sizing, comments, images, charts, data validation, protection, sheet management, streams.
references/reports-cheatsheet.md — full tag reference, named-range conventions for bands, master-detail, config sheets, user functions, events.
references/pdf-html-export.md — TFlexCelPdfExport and TFlexCelHtmlExport options: PDF/A, font embedding, digital signing, HTML5, image embedding.
references/pitfalls.md — longer list of gotchas drawn from the official Tips section: locale, fonts on Docker/Linux, barcodes, tokens in formulas, strict xlsx, conditional formats, etc.
When you need authoritative detail
The cheatsheets cover the common path. For anything deeper, fetch from the public documentation source:
- Markdown source (raw):
https://raw.githubusercontent.com/tmssoftware/TMS-FlexCel.VCL-doc-src/main/<path>.md
- Guides:
guides/api-developer-guide.md, guides/reports-developer-guide.md, guides/reports-tag-reference.md, guides/pdf-exporting-guide.md, guides/html-exporting-guide.md, guides/performance-guide.md
- Tips:
tips/<topic>.md (one file per tip)
- API reference:
api/FlexCel.XlsAdapter/TXlsFile/<MemberName>.md and similar
- Rendered docs:
https://doc.tmssoftware.com/flexcel/vcl/index.html
- Official sample repository (Delphi + C++Builder + FireMonkey):
https://github.com/tmssoftware/TMS-FlexCel.VCL-demos
Use WebFetch on the raw markdown URL when you need to confirm a signature or pull an official example. Prefer the raw markdown over the rendered HTML.
Style expectations for generated code
- Use
try..finally..Free around every FlexCel object. Don't rely on interface reference counting — these are not interfaces.
- Use 1-based literals explicitly (
SetCellValue(1, 1, ...)) — do not pretend indices are 0-based.
- Prefer the generic overloads (
TFormula.Create('=...'), TCellValue) over implicit conversions when the intent is ambiguous.
- When exporting to PDF/HTML/images, include the platform-support unit in the example's
.dpr block or mention it in a comment — otherwise rendering will fail at runtime with a missing-graphics-engine error.
- Don't invent method names. If unsure, check the API markdown under
api/<unit>/<class>/<member>.md in the doc source, or tell the user to verify with APIMate.
1---2name: flexcel-vcl3description: Use when writing Delphi / FreePascal / C++Builder code that reads, writes, manipulates, or exports Excel (.xlsx / .xls) files, generates PDF or HTML from Excel, or produces data-driven reports with FlexCel Studio for VCL and FireMonkey (TMS FlexCel). Triggers include Excel/xlsx from Delphi, TXlsFile, TFlexCelReport, TFlexCelPdfExport, TFlexCelHtmlExport, FireMonkey Excel export, Lazarus Excel, and Excel reporting from Pascal.4---5
6# FlexCel Studio for VCL / FireMonkey
7
8This skill helps write Delphi (VCL, FMX, Lazarus/LCL, Linux/SKIA) and C++Builder code that uses **FlexCel** — the TMS Software library for working with Excel `.xlsx` / `.xls` files, exporting to PDF/HTML/images, and generating data-driven reports from templates.
9
10## When to use this skill
11
12Activate whenever the user wants to, from Pascal/Delphi/C++Builder code:
13
14- **Read** an Excel file (`.xlsx` or `.xls`) — cell values, formulas, formatting.
15- **Create or modify** an Excel file programmatically.
16- **Generate reports** by merging data into Excel templates.
17- **Export** an Excel file to **PDF**, **HTML**, **SVG**, or images.
18- **Autofit** rows/columns, render sheets, or measure cells.
19- Target **VCL, FireMonkey (desktop & mobile), Lazarus, or Delphi Linux**.
20
21FlexCel does **not** require Excel or any Office installation on the target machine. It has no OLE/COM dependency.
22
23## Two ways to create Excel files — pick one
24
25Before writing code, decide which API fits the task:
26
27| If the user wants to… | Use | Why |
28|-----------------------|-----|-----|
29| Read existing files, or build files cell-by-cell in code | **`TXlsFile` API** (`FlexCel.XlsAdapter`) | Full programmatic control; no designer required. |
30| Produce the same report repeatedly from changing data, with a styled layout | **`TFlexCelReport` + Excel template** (`FlexCel.Report`) | Non-programmers can edit the template in Excel; code just provides data. |
31
32When the user says "generate a report with company logo / nice formatting / many rows from a database", prefer **Reports**. When they say "read this file and extract values" or "create an Excel file with these calculations", prefer the **API**.
33
34You can combine both: run a report to produce an in-memory `TXlsFile`, then manipulate it with the API, then export to PDF.
35
36## Quick-start recipes
37
38All examples assume VCL. For FireMonkey replace `FlexCel.VCLSupport` with `FlexCel.FMXSupport`; for Lazarus use `FlexCel.LCLSupport`; for Delphi Linux use `FlexCel.SKIASupport`. The platform support unit goes in the **main program (`.dpr`) uses clause only**, not every unit.
39
40### Recipe 1 — Create an Excel file
41
42```pascal
43uses
44 System.IOUtils,
45 FlexCel.Core, FlexCel.XlsAdapter;
46
47procedure CreateExcelFile;
48var
49 xls: TXlsFile;
50begin
51 // Start an empty workbook with 1 sheet and Excel-2019 default formatting.
52 xls := TXlsFile.Create(1, TExcelFileFormat.v2019, true);
53 try
54 xls.SetCellValue(1, 1, 'Hello from FlexCel!'); // A1 text
55 xls.SetCellValue(2, 1, 7); // A2 number
56 xls.SetCellValue(3, 1, 11.3); // A3 number
57 xls.SetCellValue(4, 1, TFormula.Create('=Sum(A2:A3)')); // A4 formula
58
59 xls.Save(TPath.Combine(TPath.GetDocumentsPath, 'test.xlsx'));
60 finally
61 xls.Free;
62 end;
63end;
64```
65
66Key points:
67- **All row/column/sheet indices are 1-based.** `(1, 1)` is cell `A1`. (XF format indices are the single exception — they're 0-based.)
68- File format is inferred from the extension (`.xlsx` → OOXML, `.xls` → BIFF8).
69- `TXlsFile` is a plain class, **not** a component — you create it in code and must `Free` it.
70
71### Recipe 2 — Read an Excel file
72
73```pascal
74uses
75 System.IOUtils,
76 FlexCel.Core, FlexCel.XlsAdapter;
77
78procedure ReadExcelFile(const aMemo: TMemo);
79var
80 xls: TXlsFile;
81 row, colIndex, XF: integer;
82 cell: TCellValue;
83 addr: TCellAddress;
84 s: string;
85begin
86 xls := TXlsFile.Create(TPath.Combine(TPath.GetDocumentsPath, 'test.xlsx'));
87 try
88 xls.ActiveSheetByName := 'Sheet1'; // or loop xls.ActiveSheet from 1 to xls.SheetCount
89 for row := 1 to xls.RowCount do
90 begin
91 // Use ColCountInRow, NOT ColCount — much faster. See performance guide.
92 for colIndex := 1 to xls.ColCountInRow(row) do
93 begin
94 XF := -1;
95 cell := xls.GetCellValueIndexed(row, colIndex, XF);
96 addr := TCellAddress.Create(row, xls.ColFromIndex(row, colIndex));
97
98 s := 'Cell ' + addr.CellRef + ' ';
99 if cell.IsEmpty then s := s + 'is empty.'
100 else if cell.IsString then s := s + 'string: ' + cell.ToString
101 else if cell.IsNumber then s := s + 'number: ' + FloatToStr(cell.AsNumber)
102 else if cell.IsBoolean then s := s + 'bool: ' + BoolToStr(cell.AsBoolean)
103 else if cell.IsError then s := s + 'error: ' + cell.ToString
104 else if cell.IsFormula then s := s + 'formula: ' + cell.AsFormula.Text;
105
106 aMemo.Lines.Add(s);
107 end;
108 end;
109 finally
110 xls.Free;
111 end;
112end;
113```
114
115Key points:
116- Iterate with **`ColCountInRow(row)`** combined with **`GetCellValueIndexed` + `ColFromIndex`** — this skips empty cells and is dramatically faster than a dense `1..ColCount` loop.
117- `TCellValue` is a discriminated-union record. Test with `IsEmpty / IsString / IsNumber / IsBoolean / IsError / IsFormula`, then extract with `ToString / AsNumber / AsBoolean / AsFormula`.
118- Excel dates are stored as numbers; detect them via the cell's format, not the value type.
119
120### Recipe 3 — Export Excel to PDF
121
122```pascal
123uses
124 FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Render;
125
126procedure XlsxToPdf(const Source, Dest: string);
127var
128 xls: TXlsFile;
129 pdf: TFlexCelPdfExport;
130begin
131 xls := TXlsFile.Create(Source);
132 try
133 pdf := TFlexCelPdfExport.Create(xls);
134 try
135 pdf.Export(Dest); // one PDF covering all visible sheets
136 finally
137 pdf.Free;
138 end;
139 finally
140 xls.Free;
141 end;
142end;
143```
144
145PDF export needs **`FlexCel.Render`** plus the platform-support unit in the main `.dpr` (the renderer uses the graphics engine for font measurement). For PDF/A, digital signatures, font embedding tuning, or multi-sheet bookmarks see `references/pdf-html-export.md`.
146
147### Recipe 4 — Run a report from a template
148
149Assume an Excel template `invoice-template.xlsx` already exists, with tags like `<#Customers.Name>` inside a named range `__Customers__` spanning the repeating row(s).
150
151```pascal
152uses
153 FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Report;
154
155procedure RunReport(Customers: TDataSet);
156var
157 report: TFlexCelReport;
158begin
159 report := TFlexCelReport.Create(true); // true = case-insensitive tags
160 try
161 report.AddTable('Customers', Customers, TDisposeMode.DoNotDispose);
162 report.SetValue('ReportDate', Now);
163 report.SetValue('CompanyName', 'Acme Corp');
164 report.Run('invoice-template.xlsx', 'invoice-output.xlsx');
165 finally
166 report.Free;
167 end;
168end;
169```
170
171To write the **output straight to PDF**, run the report into a `TXlsFile` and pipe it through `TFlexCelPdfExport`:
172
173```pascal
174out := TXlsFile.Create;
175try
176 report.Run('template.xlsx', out);
177 pdf := TFlexCelPdfExport.Create(out);
178 try pdf.Export('report.pdf'); finally pdf.Free end;
179finally
180 out.Free;
181end;
182```
183
184For the full tag language and template-design conventions see `references/reports-cheatsheet.md`.
185
186## Unit reference (what to put in `uses`)
187
188Always include **`FlexCel.Core`** in every unit that touches FlexCel types. Then add, per task:
189
190| Task | Additional units |
191|------|------------------|
192| Platform graphics (main `.dpr` only) | `FlexCel.VCLSupport` / `FlexCel.FMXSupport` / `FlexCel.LCLSupport` / `FlexCel.SKIASupport` |
193| Read / write xls/xlsx | `FlexCel.XlsAdapter` |
194| PDF / HTML / image export, autofitting | `FlexCel.Render` |
195| Low-level PDF access (sign, PDF/A options, standalone PDF) | `FlexCel.Pdf` |
196| Template-based reports | `FlexCel.Report` |
197
198## Critical gotchas (read this every time)
199
2001. **1-based indexing** for rows, columns, sheets. `SetCellValue(1, 1, ...)` writes to `A1`. (XF format indices are 0-based.)
2012. **Always `Free`** `TXlsFile`, `TFlexCelReport`, `TFlexCelPdfExport`, etc. They're plain classes, not components. Use `try..finally`.
2023. **Don't iterate with `ColCount`** — it scans the whole sheet. Use `ColCountInRow(row)` + `GetCellValueIndexed` + `ColFromIndex`.
2034. **Platform support unit belongs in the `.dpr` only**, not in every unit — it has no published types.
2045. **Dates are numbers.** `GetCellValue` returns the serial date; check the cell's number format to know it's a date.
2056. **Measurement units in Excel are unusual** — column widths are in 1/256 of a character, row heights in 1/20 of a point, etc. See the "Understanding Excel measurement units" tip in the docs before fiddling with widths/heights.
2067. **Use APIMate.** When the user asks "how do I make a cell blue / add an autofilter / create a pivot table", the canonical answer is: do it in Excel, open the file in APIMate (ships with FlexCel), and copy the generated Delphi/C++ code. APIMate is the recommended way to discover API calls for anything Excel-specific. Mention this to the user.
207
208## When to consult the references
209
210Load a reference file only when the task actually needs it — keeps your context lean.
211
212- **`references/api-cheatsheet.md`** — deeper `TXlsFile` usage: formatting, fonts, colors, merging, row/column sizing, comments, images, charts, data validation, protection, sheet management, streams.
213- **`references/reports-cheatsheet.md`** — full tag reference, named-range conventions for bands, master-detail, config sheets, user functions, events.
214- **`references/pdf-html-export.md`** — `TFlexCelPdfExport` and `TFlexCelHtmlExport` options: PDF/A, font embedding, digital signing, HTML5, image embedding.
215- **`references/pitfalls.md`** — longer list of gotchas drawn from the official Tips section: locale, fonts on Docker/Linux, barcodes, tokens in formulas, strict xlsx, conditional formats, etc.
216
217## When you need authoritative detail
218
219The cheatsheets cover the common path. For anything deeper, fetch from the public documentation source:
220
221- Markdown source (raw): `https://raw.githubusercontent.com/tmssoftware/TMS-FlexCel.VCL-doc-src/main/<path>.md`
222 - Guides: `guides/api-developer-guide.md`, `guides/reports-developer-guide.md`, `guides/reports-tag-reference.md`, `guides/pdf-exporting-guide.md`, `guides/html-exporting-guide.md`, `guides/performance-guide.md`
223 - Tips: `tips/<topic>.md` (one file per tip)
224 - API reference: `api/FlexCel.XlsAdapter/TXlsFile/<MemberName>.md` and similar
225- Rendered docs: `https://doc.tmssoftware.com/flexcel/vcl/index.html`
226- Official sample repository (Delphi + C++Builder + FireMonkey): `https://github.com/tmssoftware/TMS-FlexCel.VCL-demos`
227
228Use `WebFetch` on the raw markdown URL when you need to confirm a signature or pull an official example. Prefer the raw markdown over the rendered HTML.
229
230## Style expectations for generated code
231
232- Use `try..finally..Free` around every FlexCel object. Don't rely on interface reference counting — these are not interfaces.
233- Use 1-based literals explicitly (`SetCellValue(1, 1, ...)`) — do not pretend indices are 0-based.
234- Prefer the generic overloads (`TFormula.Create('=...')`, `TCellValue`) over implicit conversions when the intent is ambiguous.
235- When exporting to PDF/HTML/images, include the platform-support unit in the example's `.dpr` block or mention it in a comment — otherwise rendering will fail at runtime with a missing-graphics-engine error.
236- Don't invent method names. If unsure, check the API markdown under `api/<unit>/<class>/<member>.md` in the doc source, or tell the user to verify with APIMate.