Data grid — version history
A modern grid laid over a DataStore — typed columns and rich cells, sorting, filters, grouping with subtotals, in-place editing, very large volumes and CSV export — while the DataWindow stays the master of your data. Introduced in 4.0.
4.0 — October 2026 #
New #
- First release.
of_from_datastoreloads a DataStore in one call and reads what the DataWindow says about each column: its header text becomes the title, its display format and edit mask apply, a code table (Values, DropDown DataWindow, CheckBox) shows the displayed value while the row keeps the data, columns come in the order the DataWindow shows them, and a column hidden in the painter arrives hidden. Each row's key is its RowID, so it survives a sort, filter, insert or delete in the DataStore (ids.GetRowFromRowId(Long(as_key))). Regional dates and decimals are read correctly. - Columns can also be declared by code (
of_add_column,of_set_columns) and each is driven through its handle (of_column→n_pbt_datagrid_column): title, width, hidden, pinned to a side, editable, footer total, DataWindow-style display format (is_format), filter, position. - Rich cells from plain DataStore values: avatar, coloured status chip (
is_tones, colour by value), progress gauge, sparkline from a"3,5,2,6"text, star rating, tags from a"vip, b2b"text, button, link. - With no code at all, the user sorts, filters (quick search or a filter row per column, with
> 1000style operators on numbers and dates), chooses visible columns, resizes, reorders by dragging headers (a visible drop marker), pins or hides columns, selects rows Explorer-style (click, Ctrl, Shift), copies with Ctrl+C (ue_copy), and uses a row context menu (Copy, Select all, Clear selection, Export to CSV) to which you add your own entries (of_add_row_menu_item→ue_row_menu_clicked, with the whole selection). - Grouping by one or more columns with subtotals (
is_group_by, read back live), footer totals, expandable detail panel per row in rich text (of_fill_detail,ue_row_expanded), tree mode (of_expand_node). - In-place editing: typed editors (list for a code-table column, calendar for a date), invalid input shown as refused while typing, optional veto before a value is kept (
ib_veto_edits→ue_cell_editing),ue_cell_edited; withib_write_back, each entry is written into the DataStore with a typedSetItembefore the event, modified cells are marked untilof_reset_update(), andof_reload_rowrefreshes one row after your code changed it. TheUpdatestays yours. - Very large volumes: only visible rows are drawn (tens of thousands of rows scroll smoothly), automatic pagination (
ii_page_size,il_page_threshold,of_go_to_page), and a windowed source that is never held in full (of_open_source→ue_rows_needed,of_supply_rows, grand total you supply withof_supply_grand_totals). - The user's arrangement — column order, widths, pins, visibility, sort, filters, search, grouping — is read by
of_get_layout, restored byof_set_layout, and reported whole byue_layout_changed. of_export_csv(as_path)writes what the grid shows (UTF-8 with BOM, semicolon separator), confirmed byue_csv_saved; the grid is fully keyboard-driven as a single tab stop, and follows the ten themes, with row lines in every theme.ue_script_error: a script error in the page reaches PowerBuilder with its message instead of being lost.of_set_property,of_get_propertyandof_component_name: drive a property by its name (settings screen, saved configuration).- Sort on several columns: Shift+click on a header adds the column to the sort after the others (a second Shift+click turns it descending, a third takes it out), and each arrow shows its rank;
of_sort("city A, revenue D")does the same from your code, written as a DataWindow'sSetSortreads it, andue_sort_changedcarries the whole sort in that form (as_sort) — a windowed source sorts its DataStore with it. - An editable boolean column (
TYPE_BOOL, or a DataWindow CheckBox) shows a check box in each cell: a click, Space, Enter or F2 turns it over at once, through the same veto and events as a typed entry. - Detail on demand: with
ib_detail_on_demandevery row shows its chevron, and opening one raisesue_detail_needed— fill the panel there withof_fill_detail, it opens when the event returns. The detail of thousands of rows is never read up front. - Spreadsheet-like editing: typing a character on an editable text or number cell opens its editor with that character, and during an edit Tab / Shift+Tab keep the value and open the next (previous) editable cell, the grid scrolling with them line after line; closing an edit (Enter, Tab) leaves the grid where it is scrolled.
of_export_xlsx(as_path)writes what the grid shows to an Excel workbook — numbers stay numbers, with the format of their column — confirmed byue_xlsx_saved. A relative export path (CSV or Excel) is written in the folder the application started in, and the event gives the full path.ue_write_back_failed(as_key, as_col, as_value, as_reason): withib_write_back, a value the DataStore cannot keep (its row deleted since the load, a valueSetItemrefuses, a text that is not a time) is not kept — the cell goes back to what the DataStore holds and the event says why.of_from_datastorecalled again after aRetrievekeeps what your code set on the columns and their order, reads again what the DataWindow says (header text, format, code table), and places each value under its own column whatever order the user gave them.- Numbers are typed and filtered in the display language, groupings included:
1.500is fifteen hundred in German,1,234.5a number in English,> 1.000a filter above one thousand. - A three-state DataWindow CheckBox shows its third state as indeterminate, and a click cycles On, Off, Other as the DataWindow does.
- A filtered column shows a funnel on its header — and in the Columns chooser when it is hidden;
ue_filter_changedcarries every filter as typed and the search ({"filters":{"revenue":"> 1000"},"quick":"bos"}), once the typing stops. - Every change of the layout raises
ue_layout_changed, whether the user or your code made it — width, grouping, filters, search, filter row,of_set_layoutincluded — and nothing when nothing changes; a selection your code empties (a reload,SELECT_NONE) raisesue_selection_changed. - An edited row stays where it is until the next sort or filter; Ctrl+C copies the whole selection, every page of it; in a windowed source, Ctrl+End, Ctrl+Home and Page Down reach the rows not supplied yet; the pager follows the search and the filters.
SUMMARY_COUNTcounts the cells that hold a value, ascount()of a DataWindow; avatar initials work in every script (Cyrillic, Chinese, Polish…);RENDERER_BOOL(a check mark) andRENDERER_CUSTOM(the value as rich text markup) are documented.- Raw JSON given to
of_set_columns,of_load_rows,of_append_rows,of_update_row,of_select_rows,of_supply_rowsorof_supply_grand_totalsis checked first (-5when it is not a JSON array or object);of_update_rowreturns-5for a key the grid does not hold,of_append_rowswhen rows were left out because their key is already held, andof_select_rowsleaves out a key the grid does not hold.