# Virtual rows and a chart companion A VCL window with two pages, built entirely in code (`TForm.CreateNew`, no `.dfm`). It goes further than the [quick start](https://youseful.software/delphi/projects/atlas-virtual-grid-memorygridexport.html). **One million on-demand rows.** A `TAtlasVirtualData` with `RowCount = 1000000` computes every cell in `OnGetCell`. Nothing is stored except the cells the user edits, which `OnSetCell` keeps in a dictionary. The page shows: - three column bands (Source, Measurement, Review) and two frozen columns (Row, Sensor) that stay put while the wide Note column scrolls sideways; - read-only columns set on the grid (`Columns[i].ReadOnly`), because an on-demand source with an `OnSetCell` handler reports every column as writable; - in-place editing with validation. `OnSetCell` raises `EAtlasGridError` for a reading outside -50..150, a blank reading or a note longer than 40 characters. The grid keeps the editor open, leaves the data unchanged and reports the reason through `OnEditError`, which this sample shows in the status line. Text that does not parse as a number is refused before `OnSetCell` is called; - conditional colours from `OnCellStyle`: edited cells amber, readings above 100 light red, negative readings in blue text; - a Filter button that times `FilterText` over the million rows, and a Last row button that calls `SelectCell` on row 999,999. **Chart companion.** A `TAtlasPlot` with two bar series, Plan and Actual, is linked to a `TAtlasPlotData`. The grid below the chart shows one row per quarter and one column per series, with sum totals. Editing a value moves the bar. Clicking a bar selects its cell (`RowOfPoint`), and moving in the table shows the chart argument of the row (`ArgumentOfRow`). The Quarter column is read-only, and a blank value is refused with "A series value must be a number". ## Build and run Open `VirtualAndPlotGrid.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. ## What you should see - The first page opens on the first twenty or so rows: Sensor A to H repeating, readings with two decimals (row 1 reads 50.00), timestamps one minute apart from 2026-01-01 00:00, and every fifth row checked. - Click row 4's Reading, type `200` and press Enter. The status line reads "Not accepted: A reading must lie between -50 and 150" and the editor stays open. Type `142.5` and press Enter: the value is stored, the cell turns amber once the cursor leaves it, and the status line counts the edited cells. - Double-click a Checked box, or select it and press F2 or Enter: it flips at once, with no editor. A single click only selects it. - Type `Sensor C` in the box and press Filter: 125,000 of 1,000,000 rows match. In two Win32 runs while this sample was written, a filter over the million rows took 1.6 to 1.7 s and a descending sort on Reading 1.0 to 1.4 s. Unfiltered and unsorted, scrolling asks only for the cells on screen. - Last row jumps to row 1,000,000, timestamp 2027-11-26 10:39. - On the second page, change Q2's Actual to `150` and press Enter: the orange Q2 bar rises to 150 and the Actual total becomes 530.0. ## Adapting it - Replace `GetReading` with a lookup into your own storage (a file, a cache, a service) and `SetReading` with a write back to it. Raise `EAtlasGridError` to refuse a value; other exception classes are not caught by the grid. - Call `FReadings.Refresh` when the values behind `OnGetCell` change, and set `RowCount` when the number of rows changes. - Sorting, filtering and totals read every row once. On a large source, apply a filter on a button or after a pause in typing rather than on every key.