PBToolboxAI v4 ← Site

datagrid — u_pbt_datagrid #

← Référence des composants · Sommaire du guide

La grille moderne d'un DataStore : colonnes typées et cellules riches, tri, filtres, regroupement avec sous-totaux, édition sur place, pagination, source fenêtrée et export CSV — la DataWindow reste le maître de vos données.

▶ Le voir en vrai — Application de démonstration, tuile Data grid : l'aperçu, le code qui le produit et cette page, côte à côte.


En bref #

Userobjectu_pbt_datagrid
Classe d'itemsn_pbt_datagrid_column — une colonne, obtenue par of_column
Sert àPrésenter un DataStore dans une grille moderne — tri, filtres, regroupements, édition, très gros volumes — sans quitter votre DataWindow
Limite en mode démo100 lignes affichées ; exports CSV et Excel désactivés — voir le mode démo

Le positionnement #

Le datagrid n'est pas un remplaçant de la DataWindow : c'est une couche de présentation qui se pose par-dessus. Vous gardez votre SQL, vos Retrieve(), vos Update(), vos impressions — et vous gagnez une grille moderne pour l'affichage.

Il vise deux angles morts de la grille DataWindow classique :

La liaison à la base de données et la mise à jour restent hors périmètre : elles appartiennent à la DataWindow.

Le DataStore des exemples #

Tous les exemples de cette page — comme ceux de l'application de démonstration — partent du même DataStore de comptes clients, une ligne par compte : city, rep (le commercial), status, pipeline (un pourcentage), trend (sept chiffres mensuels écrits "3,5,2,6,7,4,8"), revenue et rating (une note sur cinq). La grille s'appelle uo_grid sur la fenêtre, le DataStore ids. Une ligne chargée par of_from_datastore a pour clé son RowID dans le DataStore : il ne bouge ni quand le DataStore trie, filtre, insère ou supprime. Un event vous le rend, et ids.GetRowFromRowId(Long(as_key)) est le numéro de la ligne qu'il désigne maintenant.

Un DataStore ne porte que des valeurs simples, et c'est assez pour les cellules riches : un nombre suffit à une jauge (RENDERER_PROGRESS) et à des étoiles (RENDERER_RATING), un nom à un avatar, un texte "3,5,2,6" à un mini-graphe (RENDERER_SPARKLINE) comme "vip, b2b" à des étiquettes (RENDERER_TAGS) ; la couleur d'une pastille (RENDERER_CHIP) se donne par valeur avec is_tones.


Démarrage rapide #

// open event of the window : the accounts, retrieved the way your application already does
ids = create datastore
ids.dataobject = "d_accounts"
ids.SetTransObject(SQLCA)
ids.Retrieve()

// 1. The grid reads the columns (typed) and every row of the DataStore
uo_grid.of_from_datastore(/*ads*/ ids)

// 2. The titles are the header texts of the DataWindow ; rename one if you like
uo_grid.of_column(/*key*/ "rep").is_title = "Account manager"

// 3. Rich cells : an avatar, a coloured status, a gauge, a mini chart, stars
uo_grid.of_column(/*key*/ "rep").is_renderer = n_pbt_datagrid_column.RENDERER_AVATAR
uo_grid.of_column(/*key*/ "status").is_renderer = n_pbt_datagrid_column.RENDERER_CHIP
uo_grid.of_column(/*key*/ "status").is_tones = "Active=" + n_pbt_datagrid_column.TONE_SUCCESS + "|At risk=" + n_pbt_datagrid_column.TONE_DANGER
uo_grid.of_column(/*key*/ "pipeline").is_renderer = n_pbt_datagrid_column.RENDERER_PROGRESS
uo_grid.of_column(/*key*/ "trend").is_renderer = n_pbt_datagrid_column.RENDERER_SPARKLINE
uo_grid.of_column(/*key*/ "rating").is_renderer = n_pbt_datagrid_column.RENDERER_RATING

// 4. A total, and the city stays in view
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
uo_grid.of_column(/*key*/ "city").is_pin = n_pbt_datagrid_column.PIN_START
// ue_row_clicked event of uo_grid : (string as_key)
// The key of a row loaded by of_from_datastore is its RowID : GetRowFromRowId gives
// the row it designates now, even after a sort or a delete in the DataStore.
wf_open_account(ids.GetRowFromRowId(Long(as_key)))

Propriétés #

PropriétéTypeDéfautRôle
is_selection_modestringSELECT_NONEMode de sélection : aucune, une ligne, plusieurs (Maj = plage, Ctrl = bascule)
is_densitystringDENSITY_COMFORTABLEHauteur de ligne : confortable ou compacte
is_quick_filterstring""Filtre rapide global : ne garde que les lignes dont le texte — tel qu'affiché (22/09/2026, 1 234,50) ou brut — contient cette valeur. Ce que l'utilisateur tape attend la fin de la frappe ; masqué avec une source fenêtrée
ib_filter_rowbooleanfalseAffiche la ligne de saisie de filtre sous les en-têtes (équivalent du bouton Filtres)
ib_context_menubooleantrueMenu contextuel intégré sur une ligne : Copier, Tout sélectionner, Effacer la sélection, Exporter en CSV, plus vos propres entrées (of_add_row_menu_item). Actif par défaut. Un clic droit hors de la sélection la déplace sur la ligne visée, un clic droit dedans la conserve. À false pour afficher votre propre menu depuis ue_row_rclicked
ib_veto_editsbooleanfalseDemande avant de garder une valeur saisie : lève ue_cell_editing, qui peut refuser — la cellule garde alors son ancienne valeur
ib_write_backbooleanfalseÉcrit chaque saisie dans le DataStore donné à of_from_datastore — SetItem sur la ligne que la clé désigne (son RowID, retrouvé où elle est), typé par la colonne (dates, nombres, texte, codes) — avant ue_cell_edited. L'Update reste le vôtre ; une date ou un nombre vidé devient NULL, et une valeur que le DataStore ne peut pas garder (une ligne supprimée depuis, une valeur que SetItem refuse, un texte qui n'est pas une heure) n'est pas gardée : la cellule reprend ce que tient le DataStore, ue_write_back_failed dit pourquoi, et ue_cell_edited n'est pas levé. SetItem ne joue pas la règle Validation de la colonne : vérifiez une valeur dans ue_cell_editing (ib_veto_edits)
ib_detail_on_demandbooleanfalseDétail à la demande : chaque ligne montre son chevron, et l'ouvrir (le chevron, ou of_expand_row) lève ue_detail_needed — remplissez-y le panneau par of_fill_detail, il s'ouvre au retour de l'event. Rien de rempli : la ligne reste fermée. Le détail de 5 000 lignes n'est jamais lu d'avance
is_group_bystring""Regroupe les lignes par une ou plusieurs colonnes, dans l'ordre, leurs clés jointes par | ("statut|ville") ; chaque en-tête de groupe porte les sous-totaux des colonnes qui ont un total. "" revient à une liste plate. Relue en direct
ii_page_sizeinteger100Nombre de lignes par page, une fois la pagination déclenchée
il_page_thresholdlong50000Nombre de lignes au-delà duquel la grille passe en pages. 0 = paginer toujours, quel que soit le volume
is_theme_stylestring""Style visuel du composant (constantes THEME_STYLE_*) ; vide = celui de l'application, suivi à chaque changement
is_theme_modestring""Variante claire ou sombre (constantes THEME_MODE_*) ; vide = celle de l'application, suivie à chaque changement
il_theme_accentlong-1Couleur d'accent de ce composant (-1 = l'accent de l'application, ou celui du thème)
is_tooltipstring""Info-bulle simple affichée au survol du composant
is_super_tooltip_titlestring""Titre de l'info-bulle enrichie (prend le pas sur is_tooltip)
is_super_tooltip_textstring""Texte de l'info-bulle enrichie (balisage riche accepté)
is_super_tooltip_imagestring""Image de l'info-bulle enrichie

Propriétés de colonne #

Chaque colonne est un objet à part entière, obtenu par of_column("identifiant") — le handle est créé au premier accès et reste valable ensuite.

// A column is reached by its key ; used once, it fits on one line
uo_grid.of_column(/*key*/ "amount").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
uo_grid.of_column(/*key*/ "city").is_pin = n_pbt_datagrid_column.PIN_START
PropriétéTypeDéfautRôle
is_titlestringla cléTexte d'en-tête de la colonne ; "" réaffiche la clé. of_from_datastore laisse les noms de colonnes du DataWindow : nommez-les pour l'utilisateur ici
is_tonesstring""Couleur d'une pastille (RENDERER_CHIP) selon sa valeur, pour le texte d'un DataStore : paires valeur=ton jointes par | ("Active=success|At risk=danger"), tons TONE_* ; une valeur absente reste neutre
ii_widthintegerlargeur déclaréeLargeur de la colonne, en pixels
ib_hiddenbooleanfalseMasque ou réaffiche la colonne
is_pinstringPIN_NONEFige la colonne à gauche ou à droite : elle reste visible pendant le défilement horizontal
ib_editablebooleanfalseAutorise la saisie : double-clic, saisie, Entrée valide, Échap annule → ue_cell_edited. Une valeur qui ne convient pas à la colonne (des lettres dans un nombre) est montrée refusée pendant la frappe, et Entrée garde l'éditeur ouvert. Une colonne booléenne montre une vraie case à cocher : un clic, Espace, Entrée ou F2 la retourne aussitôt. Taper un caractère sur une cellule texte ou nombre ouvre l'éditeur avec ce caractère ; pendant une édition, Tab et Maj+Tab gardent la valeur et ouvrent la cellule modifiable suivante (précédente)
is_summarystringSUMMARY_NONETotal en pied de colonne ; SUMMARY_NONE le retire. SUMMARY_COUNT compte les cellules qui ont une valeur, comme count() d'un DataWindow
is_rendererstringRENDERER_NONECellule riche appliquée après coup ; RENDERER_NONE revient au texte. RENDERER_BOOL montre une coche pour une valeur vraie ; RENDERER_CUSTOM lit la valeur comme du texte riche à balises — pour une colonne que votre code compose : une valeur saisie par un utilisateur doit avoir ses crochets échappés ([[ ]])
ii_indexintegerordre de déclarationPosition de la colonne (première position = 1) ; une colonne que la grille ne tient pas se relit 0
is_filterstring""Filtre par colonne. Le texte est cherché dans ce que la cellule affiche (date formatée, nombre masqué) ou dans sa valeur brute ; sur une colonne numérique, un opérateur en tête est reconnu ("> 1000", "<= 50", "> 1,5" avec le séparateur décimal de la langue), sur une colonne date aussi ("> 22/09/2026", dans l'ordre de la langue, ou ISO). Chaîne vide = filtre retiré
is_formatstring""Format d'affichage, dans la syntaxe du DataWindow : "#,##0.00", "$#,##0;($#,##0)", "0.0%", "dd/mm/yyyy", "mmmm d, yyyy", "hh:mm", "@@@-@@@@". Comme dans un DataWindow, la virgule et le point désignent les séparateurs de la langue. Chaîne vide = le format du DataWindow revient ; se relit (le format en vigueur)

Constantes #

Utilisez toujours les constantes plutôt que les chaînes littérales : l'IDE les complète et une faute de frappe devient impossible.

FamilleConstantesPortées par
Type de colonneTYPE_STRING, TYPE_NUMBER, TYPE_INT, TYPE_DATE, TYPE_DATETIME, TYPE_BOOLle composant (of_add_column)
Cellule richeRENDERER_AVATAR, RENDERER_CHIP, RENDERER_PROGRESS, RENDERER_SPARKLINE, RENDERER_RATING, RENDERER_TAGS, RENDERER_BUTTON, RENDERER_LINK, RENDERER_BOOL, RENDERER_CUSTOMle composant et le handle de colonne (is_renderer)
Cellule riche : aucuneRENDERER_NONEle handle de colonne uniquement (is_renderer)
Ton de pastilleTONE_SUCCESS, TONE_WARN, TONE_DANGER, TONE_INFO, TONE_NEUTRALle handle de colonne (is_tones)
Mode de sélectionSELECT_NONE, SELECT_SINGLE, SELECT_MULTIPLEle composant (is_selection_mode)
DensitéDENSITY_COMFORTABLE, DENSITY_COMPACTle composant (is_density)
Total de piedSUMMARY_NONE, SUMMARY_SUM, SUMMARY_AVG, SUMMARY_MIN, SUMMARY_MAX, SUMMARY_COUNTle handle de colonne (is_summary)
Côté d'épinglagePIN_NONE, PIN_START, PIN_END (logiques : START = bord de début de lecture)le handle de colonne (is_pin)

Les constantes se lisent sur l'objet qui les porte : u_pbt_datagrid.SELECT_MULTIPLE pour une propriété du composant, n_pbt_datagrid_column.PIN_START pour une propriété de colonne.


Méthodes #

Alimenter la grille #

MéthodeRôle
of_from_datastore (datastore ads)Le pont DataStore : lit les colonnes (nom + type PowerBuilder, typage automatique) et transfère toutes les lignes en un seul appel, avec ce que le DataWindow dit de chaque colonne — son texte d'en-tête devient le titre, son format d'affichage s'applique, et une liste de codes (Values, DropDown DataWindow, CheckBox) montre sa valeur affichée pendant que la ligne garde la donnée. Les colonnes viennent dans l'ordre où le DataWindow les montre (leur X), et une colonne masquée dans le peintre (Visible = 0) arrive masquée : l'utilisateur la réaffiche par le bouton Colonnes. Un champ calculé n'est pas une colonne du DataStore : il ne vient pas ; une DropDown DataWindow dont l'enfant n'a aucune ligne montre les codes. Rappelez-la après un Retrieve : les colonnes gardent ce qui a été posé sur elles (titre, cellule riche, épingle, largeur, total) et leur place, ce que le DataWindow dit (en-tête, format, liste de codes) est relu, et chaque valeur arrive sous sa propre colonne, quel que soit l'ordre que l'utilisateur leur a donné. La clé de chaque ligne est son RowID : elle ne bouge ni quand le DataStore trie, filtre, insère ou supprime, et ids.GetRowFromRowId(Long(as_key)) est la ligne qu'elle désigne maintenant. Rend 0 une fois appliqué, -5 quand le DataStore n'est pas valide ou n'a aucune colonne, -2 quand le composant n'est pas créé
of_add_column (string as_key, string as_title, string as_type)Ajoute une colonne à largeur automatique, après les autres : celles qui sont déjà là gardent ce qui a été posé sur elles. Pour changer une colonne ensuite, passez par sa poignée (of_column). Rend 0 une fois appliqué, -5 quand la clé est vide, contient / ou `, ou nomme une colonne que la grille a déjà, -2` quand le composant n'est pas créé
of_add_column (string as_key, string as_title, string as_type, long al_width)Idem, avec une largeur en pixels (0 = automatique). Rend 0 une fois appliqué, -5 quand la clé est vide, contient / ou `, ou nomme une colonne que la grille a déjà, -2` quand le composant n'est pas créé
of_add_column (string as_key, string as_title, string as_type, long al_width, string as_renderer)Idem, avec une cellule riche (RENDERER_*). Rend 0 une fois appliqué, -5 quand la clé est vide, contient / ou `, ou nomme une colonne que la grille a déjà, -2` quand le composant n'est pas créé
of_set_columns (string as_columns_json)Déclare toutes les colonnes d'un coup, avec leurs options fines (format, épinglage, colonne modifiable…). Les poignées de colonne obtenues avant (of_column) sont libérées : reprenez-les. Rend 0 une fois appliqué, -5 quand le texte n'est pas un tableau JSON, -2 quand le composant n'est pas créé
of_load_rows (string as_rows_json)Remplace les lignes affichées. Le DataStore d'un of_from_datastore précédent est oublié : ib_write_back et of_reload_row ne l'atteignent plus. Rend 0 une fois appliqué, -5 quand le texte n'est pas un tableau JSON, -2 quand le composant n'est pas créé
of_append_rows (string as_rows_json)Ajoute des lignes à la suite des lignes déjà affichées — défilement infini, arrivée temps réel. Rend 0 une fois appliqué, -5 quand le texte n'est pas un tableau JSON ou que des lignes en ont été écartées parce que la grille tient déjà leur clé (les autres sont ajoutées), -2 quand le composant n'est pas créé
of_update_row (string as_row_json)Remplace une ligne sur place : celle qui porte la même clé _k. Rend 0 une fois appliqué, -5 quand le texte n'est pas un objet JSON ou que la grille ne tient aucune ligne de cette clé, -2 quand le composant n'est pas créé
of_reload_row (long al_row)Renvoie une ligne du DataStore donné à of_from_datastore, lue maintenant : après que votre code l'a changée. al_row est son numéro de ligne aujourd'hui ; la grille retrouve la ligne par son RowID, un tri ou une suppression entre-temps n'y change rien. Une ligne que la grille ne tient pas encore (InsertRow, où que ce soit) s'ajoute après les autres. Rend 0 une fois envoyée, -5 quand aucun DataStore n'est lié ou que la ligne n'existe pas, -2 quand le composant n'est pas créé
of_reset_update ( )À appeler une fois votre Update réussi : les cellules modifiées dans la grille ne sont plus marquées (un petit coin dans l'accent). Rend 0 une fois envoyé, -2 quand le composant n'est pas créé
of_remove_row (string as_key)Retire une ligne, par sa clé. Pour une ligne d'un DataStore, la clé est son RowID : prenez-la avant ids.DeleteRow(ll_row), par String(ids.GetRowIdFromRow(ll_row)). Rend 0 une fois appliqué, -5 quand la grille ne tient aucune ligne de cette clé, -2 quand le composant n'est pas créé
of_clear_columns ( )Vide les colonnes accumulées par of_add_column, avant de reconstruire une grille. Les poignées de colonne obtenues avant (of_column) sont libérées : reprenez-les. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé

Colonnes #

MéthodeRôle
of_column (string as_key)Le handle d'une colonne (n_pbt_datagrid_column) : largeur, épinglage, masquage, saisie, total, cellule riche, position, filtre — voir Propriétés de colonne

Tri, filtre, présentation #

MéthodeRôle
of_sort (string as_col, string as_dir)Trie sur une seule colonne : "asc", "desc" ou "none" (retour à l'ordre chargé). Une colonne à liste de codes trie sur sa donnée, comme un DataWindow. Plusieurs colonnes : of_sort("city A, revenue D"). Rend 0 une fois trié, -5 quand la grille n'a pas cette colonne ou que le sens n'est pas l'un des trois, -2 quand le composant n'est pas créé
of_sort (string as_sort)Trie sur plusieurs colonnes, dans leur ordre : la première décide, les suivantes départagent ses égalités. as_sort s'écrit comme le SetSort d'un DataWindow le lit — "city A, revenue D" ; asc et desc sont lus aussi, une colonne sans sens est croissante, "" retire le tri (ordre chargé). Rend 0 une fois trié, -5 pour une colonne que la grille n'a pas, un autre sens ou une colonne nommée deux fois, -2 quand le composant n'est pas créé
of_get_layout ( )Ce que l'utilisateur a arrangé, en JSON : les colonnes dans leur ordre avec largeur, épingle et visibilité, le tri (un tableau ordonné : "sort":[{"col":"city","dir":"asc"},{"col":"revenue","dir":"desc"}]), les filtres tels que saisis, la recherche rapide, le regroupement et la ligne de filtres. À ranger (fichier, registre, table) puis à rendre à of_set_layout. Titres, cellules riches et formats sont les vôtres : ils n'y sont pas
of_set_layout (string as_layout_json)Remet une disposition lue par of_get_layout ou reçue par ue_layout_changed. Une colonne qu'elle ne connaît pas (ajoutée depuis) garde sa place après celles qu'elle ordonne ; une colonne qu'elle nomme et qui n'existe plus est ignorée ; ue_layout_changed est levé, comme pour tout changement de disposition. Un tri écrit en objet seul ("sort":{"col":"city","dir":"asc"}) est lu aussi. Rend 0 une fois appliquée, -5 quand le texte est vide ou n'est pas un objet JSON (un fichier tronqué : rien n'est envoyé), -2 quand le composant n'est pas créé
of_clear_filters ( )Efface le filtre rapide et tous les filtres par colonne. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé

Sélection, détail, export #

MéthodeRôle
of_select_rows (string as_keys_json)Pose la sélection depuis votre code, par liste de clés ('["1","4"]') ; un tableau vide désélectionne tout, une clé que la grille ne tient pas est écartée. Comme un clic, lève ue_selection_changed (rien si les mêmes lignes restent sélectionnées). Rend 0 une fois appliqué, -5 quand le texte n'est pas un tableau JSON, -2 quand le composant n'est pas créé
of_selected_keys ( )Renvoie les clés sélectionnées, en tableau JSON ('["1","4"]'), lues dans la grille au moment de l'appel : une sélection posée par of_select_rows, ou une ligne retirée depuis, est déjà prise en compte
of_fill_detail (string as_key, string as_markup)Panneau de détail d'une ligne, en texte riche. Rend 0 une fois appliqué, -5 quand la grille ne tient aucune ligne de cette clé, -2 quand le composant n'est pas créé
of_expand_row (string as_key) · of_collapse_row (string as_key)Déplie / replie le panneau de détail d'une ligne ; comme son chevron, lève ue_row_expanded / ue_row_collapsed (rien si le panneau est déjà dans cet état). Rend 0 une fois appliqué, -5 quand la grille ne tient aucune ligne de cette clé, -2 quand le composant n'est pas créé
of_expand_node (string as_key) · of_collapse_node (string as_key)Mode arborescent : déplie / replie un nœud (les lignes filles portent _parent). Rend 0 une fois appliqué, -5 quand la grille ne tient aucune ligne de cette clé, -2 quand le composant n'est pas créé
of_export_csv (string as_path)Écrit ce que la grille affiche (filtres, tri, colonnes visibles) dans un fichier CSV : UTF-8 avec BOM, séparateur point-virgule — le jumeau de l'export du crosstab. La DLL écrit le fichier, ue_csv_saved confirme. Refusé sans licence. Rend 0 une fois demandé, -5 quand le chemin est vide, -2 quand le composant n'est pas créé
of_export_xlsx (string as_path)Écrit ce que la grille affiche (filtres, tri, colonnes visibles) dans un classeur Excel (.xlsx) : les nombres restent des nombres, avec le format de leur colonne, la ligne d'en-tête en gras. La DLL écrit le fichier, ue_xlsx_saved confirme ; un chemin relatif s'écrit dans le dossier où l'application a démarré. Refusé sans licence et avec une source fenêtrée. Rend 0 une fois demandé, -5 quand le chemin est vide, -2 quand le composant n'est pas créé
of_add_row_menu_item (string as_key, string as_label)Ajoute une de vos entrées au menu contextuel de ligne, sous les entrées intégrées ; le choix revient dans ue_row_menu_clicked avec cette clé, un libellé vide affiche la clé. Rend 0 une fois ajoutée, -5 quand la clé est vide, contient / ou ``, ou est déjà l'une de vos entrées
of_add_row_menu_separator ( )Un séparateur entre deux groupes de vos entrées. Rend 0
of_clear_row_menu ( )Retire vos entrées : le menu de ligne revient aux seules entrées intégrées. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé

Très gros volumes #

MéthodeRôle
of_open_source (long al_total)Déclare une source de al_total lignes sans les construire : la grille réclame uniquement celles qu'elle doit afficher, via ue_rows_needed. Les clés sont alors des positions dans votre source ; le DataStore d'un of_from_datastore précédent est oublié. La recherche rapide et la ligne de filtres sont masquées (la grille ne tient que les lignes à l'écran) ; un tri choisi par l'utilisateur vous arrive par ue_sort_changed : triez votre source, la grille redemande ses lignes. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé
of_supply_rows (long al_from, string as_rows_json)Réponse à ue_rows_needed : le lot de lignes est posé à partir de la ligne al_from, comptée à partir de 1 comme celles d'un DataStore. Rend 0 une fois appliqué, -5 quand le texte n'est pas un tableau JSON, -2 quand le composant n'est pas créé
of_clear_source ( )Quitte le mode fenêtré et revient aux lignes chargées en mémoire. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé
of_go_to_page (long al_page)Affiche une page donnée (la première = 1). Sans effet tant que la pagination n'est pas déclenchée. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé
of_supply_grand_totals (string as_values_json)Pose le total général, que vous calculez : '{"ca":128400000,"quantity":51230}'. Une chaîne vide le retire. Rend 0 une fois appliqué, -5 quand le texte n'est pas un objet JSON, -2 quand le composant n'est pas créé

Communes #

MéthodeRôle
of_reset ( )Vide colonnes et lignes, et remet le composant à son état neuf. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé
of_set_redraw (boolean)Regroupe une rafale de modifications en un seul rendu. Rend 0
of_save_as_png (string) · of_save_as_jpg (string)Exporte le rendu en image. Rend 0 une fois l'image écrite, -2 composant non créé, -4 capture impossible, -5 chemin vide

Événements #

ÉvénementDéclenché quand
ue_row_clicked (string as_key)Une ligne est cliquée
ue_row_dblclicked (string as_key, string as_col)Une ligne est double-cliquée : le geste qui ouvre une fiche. as_col est la colonne sous le pointeur. Sur une cellule modifiable, le double-clic ouvre l'éditeur et ne lève pas cet event
ue_cell_clicked (string as_key, string as_col)Une cellule est cliquée
ue_selection_changed (string as_keys_json)La sélection change : un clic sélectionne cette ligne seule, Ctrl+clic en ajoute ou en retire une, Maj+clic prend une plage, et of_select_rows fait de même depuis votre code ; as_keys_json est le tableau JSON des clés sélectionnées ('["1","4"]'). Une sélection que votre code vide (un rechargement, SELECT_NONE) est dite aussi
ue_sort_changed (string as_col, string as_dir, string as_sort)Le tri a changé : un clic d'en-tête (Maj+clic ajoute une colonne au tri), le menu d'une colonne, ou of_sort — un ordre du code lève l'event comme un geste ; rien quand le tri reste le même. as_col / as_dir : la colonne dont il s'agit et son sens maintenant ("none" une fois sortie du tri) ; as_sort : le tri entier, colonnes dans leur ordre, écrit comme SetSort le lit ("city A, revenue D", "" pour aucun). Avec une source fenêtrée (of_open_source), triez votre DataStore avec lui — ids.SetSort(as_sort) puis ids.Sort() : la grille redemande ensuite ses lignes dans le nouvel ordre
ue_action_clicked (string as_key, string as_col, string as_action)Un bouton posé en cellule (RENDERER_BUTTON) est cliqué
ue_row_expanded (string as_key)Une ligne maître-détail est dépliée, par son chevron ou par of_expand_row — le bon moment pour alimenter son détail à la volée
ue_row_collapsed (string as_key)Une ligne maître-détail est repliée, par son chevron ou par of_collapse_row
ue_detail_needed (string as_key)Avec ib_detail_on_demand : une ligne qui n'a pas encore de détail s'ouvre (son chevron, ou of_expand_row). Remplissez-la ici par of_fill_detail(as_key, …) : le panneau s'ouvre au retour de l'event ; rien de rempli, la ligne reste fermée
ue_filter_changed (string as_filters_json)L'utilisateur a saisi un filtre, dans la recherche rapide ou dans la ligne de filtre par colonne (la recherche : une fois la frappe arrêtée). as_filters_json dit chaque filtre tel que saisi et la recherche — {"filters":{"revenue":"> 1000"},"quick":"bos"} : les textes que is_filter et is_quick_filter reprennent tels quels
ue_cell_edited (string as_key, string as_col, string as_value)Une cellule modifiable est validée avec une nouvelle valeur ; as_value est cette valeur en texte. Avec ib_veto_edits, seulement une fois que ue_cell_editing l'a acceptée. Avec ib_write_back, une valeur que le DataStore refuse n'est pas gardée : la cellule revient, ue_write_back_failed dit pourquoi, et cet event n'est pas levé
ue_cell_editing (string as_key, string as_col, string as_value)Avant qu'une valeur saisie soit gardée, seulement si ib_veto_edits est vrai. Rendez false pour laisser l'ancienne valeur dans la cellule (ue_cell_edited n'est alors pas levé) ; true par défaut
ue_write_back_failed (string as_key, string as_col, string as_value, string as_reason)Avec ib_write_back : le DataStore n'a pas pu garder une valeur saisie (sa ligne supprimée depuis le chargement, une valeur que SetItem refuse, un texte qui n'est pas une heure). La cellule a repris ce que tient le DataStore et ue_cell_edited n'a pas été levé ; as_reason dit pourquoi — à dire à l'utilisateur, ou recharger la ligne
ue_layout_changed (string as_layout_json)La disposition a changé, que ce soit l'utilisateur ou votre code : une colonne redimensionnée, déplacée, épinglée ou masquée, le tri, les filtres, la recherche rapide, le regroupement, la ligne de filtres — of_set_layout compris. Rien n'est levé quand rien ne change. as_layout_json est la disposition entière, telle que of_get_layout la rend : à ranger, puis à rendre à of_set_layout
ue_rows_needed (long al_from, long al_to)Mode fenêtré : la grille réclame les lignes al_from à al_to, incluses, comptées à partir de 1 — les numéros de ligne d'un DataStore. Répondez par of_supply_rows
ue_page_changed (long al_page, long al_pages)La page affichée change, par les boutons de pagination ou par of_go_to_page. al_page est la page courante (la première = 1), al_pages le nombre total de pages. Il informe seulement : avec une source fenêtrée, les lignes de la nouvelle page sont demandées par ue_rows_needed — répondez à celui-là, pas aux deux
ue_csv_saved (string as_path, boolean ab_ok, string as_error)Le CSV demandé par of_export_csv — ou par l'entrée Exporter en CSV du menu de ligne, qui demande le fichier à l'utilisateur — a été écrit, ou non : ab_ok, et as_error dit pourquoi
ue_xlsx_saved (string as_path, boolean ab_ok, string as_error)Le classeur demandé par of_export_xlsx a été écrit — ou non : ab_ok, et as_error dit pourquoi. as_path est le fichier écrit, un chemin relatif résolu
ue_copy (string as_tsv)L'utilisateur a fait Ctrl+C. as_tsv contient les lignes sélectionnées avec leur ligne d'en-tête, ou la seule cellule focalisée si rien n'est sélectionné
ue_row_rclicked (string as_key, string as_col, long al_x, long al_y)Une ligne a été cliquée droit (ou la touche Menu / Maj+F10 pressée sur elle). Déclenché que le menu intégré soit actif ou non. al_x / al_y sont des pixels écran, pas des unités PowerBuilder : pour poser votre propre menu là où l'utilisateur a visé, utilisez PopMenu(PointerX(), PointerY()) sur votre fenêtre
ue_row_menu_clicked (string as_menu_key, string as_row_key, string as_keys_json)Une de vos entrées (of_add_row_menu_item) a été choisie : as_menu_key est sa clé, as_row_key la ligne sur laquelle le menu a été ouvert ; as_keys_json est la sélection entière, sur laquelle une action de lot doit travailler
ue_ready ( )Le composant a fini de charger ; tout ce qui a été envoyé avant a été rejoué
ue_runtime_missing ( )Le runtime WebView2 est absent : le composant reste vide
ue_bg_color (long al_color)Le composant a calculé sa couleur de fond de thème ; l'userobject l'a déjà adoptée (backcolor)

Ce que l'utilisateur peut faire sans une ligne de code #

La grille embarque sa propre barre d'outils et ses menus d'en-tête. Rien de tout cela ne demande de code de votre part :

Toute modification de disposition remonte dans ue_layout_changed : largeurs, ordre, colonnes figées ou masquées. Conservez ce contenu, et rendez-le d'un seul appel à of_set_layout à la prochaine ouverture ; of_get_layout le relit à tout moment.

Au clavier — la grille est un seul arrêt de tabulation. Une fois atteinte, elle se parcourt entièrement au clavier :

ToucheEffet
FlèchesDéplacent la cellule focalisée, cellule par cellule
Début / FinPremière / dernière colonne de la ligne
Ctrl+Début / Ctrl+FinPremière / dernière cellule de la grille
Page haut / Page basSe déplacent d'un écran, en suivant la hauteur réelle de la vue
Maj + flèchesÉtendent la sélection depuis l'ancre (mode SELECT_MULTIPLE)
EspaceSélectionne ou désélectionne la ligne focalisée, et y pose l'ancre ; sur une case à cocher éditable, la retourne
Entrée ou F2Passe la cellule en édition si sa colonne est éditable ; une case à cocher se retourne aussitôt
Un caractèreSur une cellule texte ou nombre modifiable, ouvre l'éditeur avec ce caractère, comme un tableur
Tab / Maj+Tab (en édition)Garde la valeur et ouvre la cellule modifiable suivante (précédente), la ligne suivante au bout d'une ligne
Ctrl+CCopie la sélection — voir ue_copy

La cellule focalisée est entourée d'un liseré à la couleur d'accent, et annoncée aux lecteurs d'écran par aria-activedescendant. Le focus survit au défilement : la grille étant virtualisée, il est tenu en mémoire et reposé après chaque rendu. Il disparaît en revanche si sa ligne sort de la vue par un tri ou un filtre.

⚠️ Le presse-papiers du navigateur peut être refusé dans une WebView hébergée. C'est pour cette raison que ue_copy vous remet le texte : posez-le vous-même avec ClipBoard(as_tsv) pour être certain du résultat.


Exemples #

Des comptes clients en quelques lignes #

// ids : the accounts DataStore (see above). One repaint for the whole setup.
uo_grid.of_set_redraw(/*on*/ false)

// 1. The grid reads the columns (typed) and every row of the DataStore
uo_grid.of_from_datastore(/*ads*/ ids)

// 2. The titles are the header texts of the DataWindow ; rename one if you like
uo_grid.of_column(/*key*/ "rep").is_title = "Account manager"

// 3. Rich cells : an avatar, a coloured status, a gauge, a mini chart, stars
uo_grid.of_column(/*key*/ "rep").is_renderer = n_pbt_datagrid_column.RENDERER_AVATAR
uo_grid.of_column(/*key*/ "status").is_renderer = n_pbt_datagrid_column.RENDERER_CHIP
uo_grid.of_column(/*key*/ "status").is_tones = "Active=" + n_pbt_datagrid_column.TONE_SUCCESS + "|At risk=" + n_pbt_datagrid_column.TONE_DANGER
uo_grid.of_column(/*key*/ "pipeline").is_renderer = n_pbt_datagrid_column.RENDERER_PROGRESS
uo_grid.of_column(/*key*/ "trend").is_renderer = n_pbt_datagrid_column.RENDERER_SPARKLINE
uo_grid.of_column(/*key*/ "rating").is_renderer = n_pbt_datagrid_column.RENDERER_RATING

// A total, a column that stays in view, several rows selectable
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
uo_grid.of_column(/*key*/ "city").is_pin = n_pbt_datagrid_column.PIN_START
uo_grid.is_selection_mode = u_pbt_datagrid.SELECT_MULTIPLE
uo_grid.of_set_redraw(/*on*/ true)

Regrouper par statut, puis par ville #

// The subtotal every group header shows
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM

// Two levels : the status, then the city inside it ; "" goes back to a flat list
uo_grid.is_group_by = "status|city"

// The rating stays in view on the right
uo_grid.of_column(/*key*/ "rating").is_pin = n_pbt_datagrid_column.PIN_END

Filtrer depuis votre code #

// The filter row under the headers : the user types in it
uo_grid.ib_filter_row = true

// Only the accounts in Paris, and only those above one million
uo_grid.is_quick_filter = "Paris"
uo_grid.of_column(/*key*/ "revenue").is_filter = "> 1000000"

Trier sur plusieurs colonnes #

Le tri s'écrit comme celui d'un DataWindow : la première colonne décide, les suivantes départagent. L'utilisateur fait de même à la souris par Maj+clic sur les en-têtes ; un clic simple repart d'une seule colonne.

// City first, then the largest revenue in each city
uo_grid.of_sort(/*sort*/ "city A, revenue D")

Ce que la grille lit dans le DataWindow #

of_from_datastore ne prend pas que les données : le texte d'en-tête de chaque colonne (<colonne>_t) devient son titre, son format d'affichage (Format, ou le masque d'un EditMask) s'applique, et une liste de codes — Values d'un Edit, d'une DDLB ou de boutons radio, DropDown DataWindow, CheckBox — montre la valeur affichée (Active) quand la ligne garde la donnée (A). On trie et on cherche sur ce qu'on voit ; une colonne à liste s'édite par une liste, et c'est la donnée qui revient.

// The grid reads titles, formats and code tables in the DataWindow
uo_grid.of_from_datastore(/*ads*/ ids)

// A format of your own on one column, in the DataWindow's syntax
uo_grid.of_column(/*key*/ "revenue").is_format = "$#,##0.00;($#,##0.00)"

// The rating is picked in its code table (Poor to Excellent) ; the number goes into the DataStore
uo_grid.of_column(/*key*/ "rating").ib_editable = true
uo_grid.ib_write_back = true

// Your code changed a row of the DataStore : show it again
ids.SetItem(12, "rating", 5)
uo_grid.of_reload_row(/*row*/ 12)

Modifier sur place, enregistrer dans le DataStore #

La grille modifie, le DataStore garde la vérité : avec ib_write_back, chaque saisie y est écrite sur la ligne que la clé désigne (son RowID, retrouvé où elle est), typée par la colonne, avant ue_cell_edited — et la jauge suit. Une cellule modifiée garde un petit coin dans l'accent jusqu'à of_reset_update.

// The pipelines can be edited : double-click, type a percentage, Enter
uo_grid.of_column(/*key*/ "pipeline").ib_editable = true

// Every edit goes into the DataStore itself, on the row the key designates
uo_grid.ib_write_back = true

Une colonne booléenne rendue éditable (TYPE_BOOL, ou une colonne CheckBox d'un DataWindow lue par of_from_datastore) montre une vraie case à cocher dans chaque cellule : un clic, Espace, Entrée ou F2 la retourne aussitôt — pas d'éditeur de texte, et un double-clic ne la retourne pas deux fois. La cellule reçoit la valeur de l'autre état — true/false, ou les valeurs ON/OFF de la CheckBox du DataWindow — par le même chemin qu'une saisie : véto ib_veto_edits / ue_cell_editing, puis ue_cell_edited, marque « modifiée » et ib_write_back. En lecture seule, une colonne booléenne garde sa coche ✓.

// A yes/no column the user ticks : a check box in every cell
uo_grid.of_add_column(/*key*/ "vip", /*title*/ "VIP", /*type*/ u_pbt_datagrid.TYPE_BOOL)
uo_grid.of_column(/*key*/ "vip").ib_editable = true
// Saving stays with the DataStore : when the user confirms
if ids.Update() = 1 then
	COMMIT USING SQLCA;

	// the edited cells are no longer marked as modified
	uo_grid.of_reset_update()
else
	ROLLBACK USING SQLCA;
end if

Une ligne dépliable, écrite depuis le DataStore #

// Local variables
long ll_row

// A detail panel for the first 20 accounts, written from their DataStore row
for ll_row = 1 to 20
    uo_grid.of_fill_detail(/*key*/ String(ll_row), /*markup*/ "[b]" + ids.GetItemString(ll_row, "rep") + "[/b] follows the " + ids.GetItemString(ll_row, "city") + " account")
next

// The first one is open right away ; the chevron opens the others
uo_grid.of_expand_row(/*key*/ "1")

Des pages plutôt qu'un défilement, et le total de tout #

Une fois paginée, la grille ne tient qu'une page : son pied totalise la page. Le total de tous les comptes, c'est le DataStore qui l'a.

// Local variables
n_pbt_json lnv_totals
double ld_revenue
long ll_row

// Pages of 25 rows past 100 rows ; the footer totals the page
uo_grid.ii_page_size = 25
uo_grid.il_page_threshold = 100
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM

// The grand total of ALL the accounts, from the DataStore
for ll_row = 1 to ids.RowCount()
    ld_revenue = ld_revenue + ids.GetItemDecimal(ll_row, "revenue")
next
lnv_totals.of_set_number(/*path*/ "revenue", /*value*/ ld_revenue)
uo_grid.of_supply_grand_totals(/*values_json*/ lnv_totals.of_text())

Une source que la grille ne tient jamais entière #

Pour des centaines de milliers de lignes, la grille n'apprend que leur nombre et réclame celles qu'elle affiche. C'est ici que votre application lit la tranche demandée en base ; les numéros de ligne partent de 1, comme ceux du DataStore.

// The grid only learns HOW MANY rows exist ; it asks for the ones on screen
uo_grid.of_open_source(/*total*/ ids.RowCount())
// ue_rows_needed event of uo_grid : (long al_from, long al_to)
// Rows al_from to al_to, both included, counted from 1 like the DataStore
n_pbt_json lnv_row
string ls_rows
long ll_row

// One JSON row per DataStore row asked for, its key being the row number
ls_rows = "["
for ll_row = al_from to Min(al_to, ids.RowCount())
    lnv_row.of_clear()
    lnv_row.of_set_string(/*path*/ "_k", /*value*/ String(ll_row))
    lnv_row.of_set_string(/*path*/ "city", /*value*/ ids.GetItemString(ll_row, "city"))
    lnv_row.of_set_string(/*path*/ "rep", /*value*/ ids.GetItemString(ll_row, "rep"))
    lnv_row.of_set_string(/*path*/ "trend", /*value*/ ids.GetItemString(ll_row, "trend"))
    lnv_row.of_set_number(/*path*/ "revenue", /*value*/ Double(ids.GetItemDecimal(ll_row, "revenue")))
    if ll_row > al_from then ls_rows = ls_rows + ","
    ls_rows = ls_rows + lnv_row.of_text()
next
uo_grid.of_supply_rows(/*from*/ al_from, /*rows_json*/ ls_rows + "]")
// ue_sort_changed event of uo_grid : (string as_col, string as_dir, string as_sort)
// as_sort is the whole sort, written as SetSort reads it ("" for none) :
// sort the source with it, the grid then asks for its rows again
ids.SetSort(as_sort)
ids.Sort()

Exporter ce qui est affiché #

// What is shown - filters, sort, visible columns - to a CSV file
uo_grid.of_export_csv(/*path*/ "C:\exports\accounts.csv")
// ue_csv_saved event of uo_grid : (string as_path, boolean ab_ok, string as_error)
if ab_ok then
    st_status.Text = "Written : " + as_path
else
    st_status.Text = as_error
end if

Vos entrées dans le menu de ligne #

// The row menu, entry by entry
uo_grid.of_add_row_menu_item(/*key*/ "open", /*label*/ "Open the account")
uo_grid.of_add_row_menu_separator()
uo_grid.of_add_row_menu_item(/*key*/ "call", /*label*/ "Call the sales rep")
// ue_row_menu_clicked event of uo_grid : (string as_menu_key, string as_row_key, string as_keys_json)
choose case as_menu_key
    case "open"
        wf_open_account(Long(as_row_key))
    case "call"
        wf_call(ids.GetItemString(Long(as_row_key), "rep"))
end choose

Réagir à la sélection #

// ue_selection_changed event of uo_grid : (string as_keys_json)
// '["3","7"]' : the RowIDs of the selected accounts (ids.GetRowFromRowId gives their rows)
cb_delete.Enabled = (Pos(as_keys_json, "[]") = 0)

Retenir la disposition de l'utilisateur #

// ue_layout_changed event of uo_grid : (string as_layout_json)
// Order, widths, pins, hidden columns, sort, filters, grouping : keep it
SetProfileString(gs_ini, "grids", "accounts", as_layout_json)
// open event of the window, once the grid is filled : the layout of last time
uo_grid.of_set_layout(/*layout_json*/ ProfileString(gs_ini, "grids", "accounts", ""))

Bonnes pratiques #

Hérité du socle commun #

Ces membres existent sur tous les composants visuels — ils ne sont pas propres à celui-ci. Ils sont détaillés une seule fois, dans les chapitres transverses ; cette table dit seulement où les lire.

MembresRôleDétaillé dans
of_count · of_keys_at · of_hasParcourir ce que le composant contient3.2 Les items
of_resetRemettre le composant à zéro3.6 Remettre un composant à zéro : of_reset()
of_register_shortcut · of_clear_shortcutsRaccourcis clavier du composant3.5 Les raccourcis clavier
of_is_created · of_is_ready · of_get_last_errorS'il est né, s'il est prêt, ce qui a échoué3.7 Diagnostic
of_save_as_png · of_save_as_jpgExporter le rendu en image3.8 Exporter le rendu en image
of_set_redrawGrouper les modifications en un seul repaint3.10 Bonnes pratiques
of_preload_iconsIcônes affichées sans délaiAffichage instantané : of_icon
of_set_translationTraduire un libellé du composant5.2 Adapter un libellé : of_set_translation
of_focus_webviewDonner le focus au composant6.4 Clavier et focus
of_print · of_print_to_pdfImprimer, ou écrire un PDF6.9 Imprimer
of_set_property · of_get_property · of_component_namePiloter une propriété par son nom3.1 Le moteur de propriétés

Deux aides ne sont pas héritées : of_icon et of_escape_markup vivent sur n_pbt_utils. Déclarez-en une — n_pbt_utils lnv_utils, rien à créer — et appelez-les dessus.

← Référence des composants · Sommaire du guide