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('