YOUSEFUL / DELPHI / SAMPLE PROJECTS
Memory grid export
The quick start for Atlas Virtual Grid, and the project behind the tutorial. A console program that never shows a window:
- fills a
TAtlasMemoryDatawith six typed columns (number, text, date, yes/no) from invariant text, and shows that a row with a bad value is refused whole; - binds a
TAtlasVirtualGrid, which creates one column per data column, then sets format masks, bands and count/sum/average totals; - sorts ascending and descending, filters on the formatted text, and checks that totals follow the filter;
- edits through the data source and shows the grid following it, including refused values and a read-only column;
- copies the selection as tab-separated text;
- writes
orders.csv,orders.html,orders.svgandorders.png.
Every step checks its own result and raises on a mismatch, so the exit code is 0 only when everything matched.
Build and run
Open MemoryGridExport.dpr in Delphi 13; the IDE creates the project file. Add the Atlas Virtual Grid src folder and the Atlas Plot src folder to the project's search path, then build and run for Win32 or Win64. No packages need to be installed. The program needs no input. It checks its own results and stops with an error if any of them differs from the output below.
Expected output
1. Columns and rows
ok: 6 rows, 6 columns
ok: a row with a value that does not fit its column is rejected whole
2. Bind the grid and describe the columns
ok: columns were created from the source
ok: cells are formatted per column
ok: totals: count 6, quantity sum 27, average price 229.21
3. Sort
ok: ascending by customer; equal keys keep source order
ok: descending by quantity; the null quantity comes last
4. Filter
ok: 2 Fabrikam rows, still sorted
ok: totals follow the filter
ok: the filter reads the formatted date text: 3 rows shipped before 10 January
ok: filter and sort removed
5. Edit through the data source
ok: the grid follows the source: sum is now 32
ok: text that is not a number is refused and the value kept
ok: the read-only key column refuses writes
6. Selection text
ok: tab-separated formatted rows, ready for the clipboard
7. Text output
Order,Customer,Shipped,Quantity,Unit price,Paid
1001,Contoso,2026-01-05,4,125.5,true
1002,Fabrikam,2026-01-06,12,40,false
1003,Northwind,2026-01-09,1,980,true
1004,Contoso,2026-01-12,5,125.5,false
1005,"Tailspin, Ltd",2026-01-15,7,64.25,true
1006,Fabrikam,,3,40,true
ok: CSV carries raw values: invariant numbers, ISO dates, true/false
ok: commas are quoted; nulls are empty
ok: hidden columns are left out
ok: HTML has the caption, bands and totals
8. Pictures and files
ok: SVG of the visible part of the grid
ok: orders.csv written to ...\MemoryGridExport
ok: orders.html written to ...
ok: orders.svg written to ...
ok: orders.png written to ...
ok: unknown extensions are refused
MemoryGridExport: all checks passedorders.png shows two band headings (Shipment, Amount), right-aligned
numbers and dates, check boxes for the Paid column and a footer with 6, 32 and
229.21.
Adapting it
- Replace the
AddRowcalls with your own data. Values are read with invariant settings ('.'decimals, ISO dates,yes/no); useSetCellwithTAtlasCell.OfNumberand friends when you already have typed values. - The program sets
FormatSettings := TFormatSettings.Invariantso that its checks hold on every machine. In a real application leave the user's settings alone: the grid's formatted text (CellText, HTML, pictures) follows them, while CSV stays invariant. - The pictures draw what would be on screen, starting at
TopRow. For every row, use CSV or HTML.
Project files
The ZIP contains every sample project with its README. See getting started for the search path to add.
Source
MemoryGridExport.dpr
program MemoryGridExport;
// Atlas Virtual Grid quick start: an in-memory data source, a grid bound to it,
// sorting, filtering, totals, programmatic edits and CSV/HTML/SVG/PNG output.
// No window is shown; the grid works without a parent. Every result is checked.
{$APPTYPE CONSOLE}
uses
Winapi.Windows, System.SysUtils, System.Classes, System.IOUtils, Atlas.VGridData, Atlas.VGrid;
procedure Verify(Condition: Boolean; const What: string);
begin
if not Condition then raise Exception.Create('Check failed: ' + What);
Writeln(' ok: ', What);
end;
function Rejected(const Action: TProc): Boolean;
begin
Result := False;
try
Action();
except
on EAtlasGridError do Result := True;
end;
end;
procedure Run;
var
Orders: TAtlasMemoryData;
Grid: TAtlasVirtualGrid;
Csv, Html, Svg: string;
Line: string;
begin
Orders := TAtlasMemoryData.Create(nil);
Grid := TAtlasVirtualGrid.Create(nil);
try
Writeln('1. Columns and rows');
Orders.AddColumn('Order', ckNumber, True); // read-only key
Orders.AddColumn('Customer'); // ckText by default
Orders.AddColumn('Shipped', ckDateTime);
Orders.AddColumn('Quantity', ckNumber);
Orders.AddColumn('Unit price', ckNumber);
Orders.AddColumn('Paid', ckBoolean);
Orders.BeginUpdate; // one change notification for the batch
try
// One invariant text per column: '.' decimals, ISO dates, yes/no. Empty text is null.
Orders.AddRow(['1001', 'Contoso', '2026-01-05', '4', '125.50', 'yes']);
Orders.AddRow(['1002', 'Fabrikam', '2026-01-06', '12', '40', 'no']);
Orders.AddRow(['1003', 'Northwind', '2026-01-09', '1', '980', 'yes']);
Orders.AddRow(['1004', 'Contoso', '2026-01-12', '', '125.50', 'no']);
Orders.AddRow(['1005', 'Tailspin, Ltd', '2026-01-15', '7', '64.25', 'yes']);
Orders.AddRow(['1006', 'Fabrikam', '', '3', '40', 'yes']);
finally
Orders.EndUpdate;
end;
Verify((Orders.RowCount = 6) and (Orders.ColumnCount = 6), '6 rows, 6 columns');
Verify(Rejected(procedure begin Orders.AddRow(['1007', 'Adatum', '2026-02-01', 'twelve', '10', 'no']); end)
and (Orders.RowCount = 6), 'a row with a value that does not fit its column is rejected whole');
Writeln('2. Bind the grid and describe the columns');
Grid.Data := Orders; // one grid column per data column
Grid.Columns[0].Format := '0';
Grid.Columns[0].Total := tkCount;
Grid.Columns[1].Band := 'Shipment';
Grid.Columns[2].Band := 'Shipment';
Grid.Columns[2].Format := 'yyyy-mm-dd';
Grid.Columns[3].Band := 'Amount';
Grid.Columns[3].Total := tkSum;
Grid.Columns[4].Band := 'Amount';
Grid.Columns[4].Format := '#,##0.00';
Grid.Columns[4].Total := tkAverage;
Verify(Grid.Columns.Count = 6, 'columns were created from the source');
Verify((Grid.CellText(1, 4) = 'Tailspin, Ltd') and (Grid.CellText(4, 0) = '125.50') and
(Grid.CellText(5, 1) = 'No') and (Grid.CellText(3, 3) = ''), 'cells are formatted per column');
Verify((Grid.TotalText(0) = '6') and (Grid.TotalText(3) = '27') and (Grid.TotalText(4) = '229.21'),
'totals: count 6, quantity sum 27, average price 229.21');
Writeln('3. Sort');
Grid.Sort(1); // by customer, ascending, ignoring case
Verify((Grid.CellText(1, 0) = 'Contoso') and (Grid.DataRowOf(0) = 0) and (Grid.DataRowOf(1) = 3) and
(Grid.CellText(1, 5) = 'Tailspin, Ltd'), 'ascending by customer; equal keys keep source order');
Grid.Sort(3, True); // by quantity, descending
Verify((Grid.CellText(3, 0) = '12') and (Grid.DataRowOf(5) = 3), 'descending by quantity; the null quantity comes last');
Writeln('4. Filter');
Grid.FilterText := 'fab'; // any visible column, formatted text, ignoring case
Verify((Grid.RowCount = 2) and (Grid.DataRowOf(0) = 1) and (Grid.DataRowOf(1) = 5), '2 Fabrikam rows, still sorted');
Verify((Grid.TotalText(0) = '2') and (Grid.TotalText(3) = '15') and (Grid.TotalText(4) = '40.00'), 'totals follow the filter');
Grid.FilterText := '2026-01-0';
Verify(Grid.RowCount = 3, 'the filter reads the formatted date text: 3 rows shipped before 10 January');
Grid.FilterText := '';
Grid.Sort(-1); // back to source order
Verify((Grid.RowCount = 6) and (Grid.SortColumn = -1), 'filter and sort removed');
Writeln('5. Edit through the data source');
Orders.SetText(3, 3, '5', TFormatSettings.Invariant);
Verify((Grid.CellText(3, 3) = '5') and (Grid.TotalText(3) = '32'), 'the grid follows the source: sum is now 32');
Verify(Rejected(procedure begin Orders.SetText(3, 3, 'five', TFormatSettings.Invariant); end) and
(Grid.CellText(3, 3) = '5'), 'text that is not a number is refused and the value kept');
Verify(Rejected(procedure begin Orders.SetCell(0, 0, TAtlasCell.OfNumber(1)); end), 'the read-only key column refuses writes');
Writeln('6. Selection text');
Grid.SelectAll;
Line := Grid.SelectionText;
Verify((Grid.SelectedCount = 6) and Line.StartsWith('1001'#9'Contoso'#9'2026-01-05'#9'4'#9'125.50'#9'Yes'#13#10),
'tab-separated formatted rows, ready for the clipboard');
Writeln('7. Text output');
Csv := Grid.ToCSV;
Writeln(Csv);
Verify(Csv.StartsWith('Order,Customer,Shipped,Quantity,Unit price,Paid'#13#10'1001,Contoso,2026-01-05,4,125.5,true'),
'CSV carries raw values: invariant numbers, ISO dates, true/false');
Verify((Pos('"Tailspin, Ltd"', Csv) > 0) and (Pos('1006,Fabrikam,,3,40,true', Csv) > 0), 'commas are quoted; nulls are empty');
Grid.Columns[5].Visible := False;
Verify(Grid.ToCSV.StartsWith('Order,Customer,Shipped,Quantity,Unit price'#13#10), 'hidden columns are left out');
Grid.Columns[5].Visible := True;
Html := Grid.ToHTML('Orders');
Verify((Pos('<caption>Orders</caption>', Html) > 0) and (Pos('<th colspan="2">Amount</th>', Html) > 0) and
(Pos('<tfoot>', Html) > 0) and (Pos('>229.21<', Html) > 0), 'HTML has the caption, bands and totals');
Writeln('8. Pictures and files');
Grid.ClearSelection; // pictures show the selection too
Svg := Grid.ToSVG(800, 300);
Verify((Pos('<svg', Svg) > 0) and (Pos('Northwind', Svg) > 0), 'SVG of the visible part of the grid');
Grid.SaveToFile('orders.csv'); // everything
Grid.SaveToFile('orders.html'); // everything, formatted, with totals
Grid.SaveToFile('orders.svg', 800, 300); // what is on screen
Grid.SaveToFile('orders.png', 800, 300);
for Line in ['orders.csv', 'orders.html', 'orders.svg', 'orders.png'] do
Verify(TFile.Exists(Line) and (TFile.GetSize(Line) > 100), Line + ' written to ' + TDirectory.GetCurrentDirectory);
Verify(Rejected(procedure begin Grid.SaveToFile('orders.xlsx'); end), 'unknown extensions are refused');
finally
Grid.Free;
Orders.Free;
end;
end;
begin
// Formatting follows the global FormatSettings; fix them so the checks hold on every machine.
FormatSettings := TFormatSettings.Invariant;
try
Run;
Writeln('MemoryGridExport: all checks passed');
except
on E: Exception do
begin
Writeln('MemoryGridExport failed: ', E.ClassName, ': ', E.Message);
ExitCode := 1;
end;
end;
end.