sgcHTML vient de s'enrichir de 25 composants, et ceci est le premier d'une série de cinq articles qui les présente par thème. Nous commençons par quatre composants construits autour de données structurées et changeantes : TreeGrid pour les lignes hiérarchiques, PivotTable pour les agrégats groupés, ActivityFeed pour un flux d'événements en direct, et Splitter pour la mise en page à deux volets redimensionnables qui doit si souvent accueillir tout ce qui précède. Chaque composant ci-dessous est une simple classe Delphi/C++Builder/.NET : définissez ses propriétés, appelez HTML, récupérez du balisage Bootstrap 5 en retour. Aucun framework JavaScript, aucune étape de build.
TreeGrid — tableaux hiérarchiques repliables
TsgcHTMLComponent_TreeGrid génère un tableau Bootstrap dont les lignes se replient et se déplient, construit à partir de simples paires de nœuds Id / ParentId — la même structure que vous utilisez déjà pour les organigrammes, les arborescences de catégories ou les nomenclatures imbriquées. Déclarez un TsgcHTMLTreeGridColumn par champ visible, puis ajoutez des nœuds ; la relation parent/enfant dessine l'arbre et les flèches de repliement pour vous.
uses
sgcHTML_Component_TreeGrid;
var
oTreeGrid: TsgcHTMLComponent_TreeGrid;
oColumn: TsgcHTMLTreeGridColumn;
begin
oTreeGrid := TsgcHTMLComponent_TreeGrid.Create(nil);
try
oTreeGrid.TreeGridID := 'orgchart';
oTreeGrid.Sortable := True;
oColumn := oTreeGrid.Columns.Add;
oColumn.Caption := 'Department';
oColumn.FieldName := 'Name';
oColumn := oTreeGrid.Columns.Add;
oColumn.Caption := 'Headcount';
oColumn.FieldName := 'Headcount';
oColumn.Align := tgaRight;
oTreeGrid.AddNode('eng', '', ['Engineering', '42']);
oTreeGrid.AddNode('eng-be', 'eng', ['Backend', '18']);
oTreeGrid.AddNode('eng-fe', 'eng', ['Frontend', '15']);
WebModule.Response := oTreeGrid.HTML; // hierarchical table + scoped CSS + toggle script
finally
oTreeGrid.Free;
end;
end;
// Or bind it straight to a self-referencing dataset (Id / ParentId columns):
oTreeGrid.LoadFromDataSet(qryDepartments, 'Id', 'ParentId');
Si vos données se trouvent déjà dans une table auto-référencée, inutile d'appeler les nœuds manuellement : confiez à LoadFromDataSet les noms des champs parent et enfant — elle parcourt le jeu de données et construit tout l'arbre en une seule passe.
PivotTable — grouper, agréger, totaliser
TsgcHTMLComponent_PivotTable prend des lignes plates et produit un tableau groupé et agrégé avec totaux de lignes, totaux de colonnes et un total général, le rapport que vous construiriez sinon à la main dans un tableur. Vous déclarez RowFields et ColumnFields pour le regroupement, une ou plusieurs Measures à agréger (somme, moyenne, nombre, min, max), et une liste DataFields indiquant quelles colonnes source lire réellement.
uses
sgcHTML_Component_PivotTable;
var
oPivot: TsgcHTMLComponent_PivotTable;
oMeasure: TsgcHTMLPivotMeasure;
begin
oPivot := TsgcHTMLComponent_PivotTable.Create(nil);
try
oPivot.Caption := 'Revenue by Region and Quarter';
oPivot.RowFields.Add.FieldName := 'Region';
oPivot.ColumnFields.Add.FieldName := 'Quarter';
oMeasure := oPivot.Measures.Add;
oMeasure.SourceField := 'Amount';
oMeasure.Caption := 'Revenue';
oMeasure.Aggregation := paSum;
oMeasure.Format := '#,##0.00';
oPivot.DataFields.Add('Region');
oPivot.DataFields.Add('Quarter');
oPivot.DataFields.Add('Amount');
oPivot.AddRow(['EMEA', 'Q1', '12000']);
oPivot.AddRow(['EMEA', 'Q2', '15500']);
oPivot.AddRow(['APAC', 'Q1', '9800']);
WebModule.Response := oPivot.HTML; // aggregated table + row/column/grand totals
finally
oPivot.Free;
end;
end;
// Or bind it straight to a dataset (reads only RowFields/ColumnFields/Measures fields):
oPivot.LoadFromDataSet(qrySales);
Tout ce qui suit AddRow (ou LoadFromDataSet) est calculé pour vous : le composant regroupe les lignes brutes, applique l'agrégation choisie par cellule, et ajoute automatiquement les lignes et colonnes de totaux de lignes, de colonnes et le total général.
ActivityFeed — un flux d'événements en direct et diffusable
TsgcHTMLComponent_ActivityFeed affiche une liste « qui a fait quoi », triée du plus récent au plus ancien, avec des horodatages relatifs (« il y a 3 min », maintenus à jour côté client), et il est conçu dès le départ pour recevoir des mises à jour via WebSockets, et pas seulement pour être rendu une seule fois. MaxItems en fait un tampon circulaire — l'entrée la plus ancienne disparaît automatiquement une fois la limite atteinte.
uses
sgcHTML_Enums, sgcHTML_Component_ActivityFeed;
var
oFeed: TsgcHTMLComponent_ActivityFeed;
begin
oFeed := TsgcHTMLComponent_ActivityFeed.Create(nil);
try
oFeed.FeedID := 'timeline';
oFeed.Title := 'Recent Activity';
oFeed.MaxItems := 30;
oFeed.AddActivity('Ana', 'closed', 'ticket #482', hcSuccess, 'bi bi-check-circle');
oFeed.AddActivity('Marc', 'commented on', 'invoice #1190', hcPrimary);
WebModule.Response := oFeed.HTML; // feed list + scoped CSS + live relative-time script
finally
oFeed.Free;
end;
end;
// Push a new item live to connected clients (out-of-band htmx fragment):
oFeed.AddActivity('Ana', 'approved', 'purchase order #77', hcSuccess);
Engine.BroadcastFragment(oFeed.GetLastItemFragmentHTML);
Cette dernière ligne est la partie intéressante : GetLastItemFragmentHTML ne rend que l'entrée la plus récente sous forme de fragment htmx hors bande (out-of-band), et BroadcastFragment le diffuse à tous les navigateurs ouverts via le serveur sgcWebSockets que vous faites déjà tourner. Aucun polling, aucune couche temps réel séparée à mettre en place.
Splitter — la structure à deux volets qui accueille tout
TsgcHTMLComponent_Splitter est la pièce de mise en page : deux volets redimensionnables séparés par une poignée déplaçable, horizontale ou verticale, avec des minimums en pixels de chaque côté afin qu'aucun volet ne puisse être réduit à rien. C'est exactement la structure dont a besoin un écran TreeGrid-plus-panneau-de-détail ou liste-de-fichiers-plus-éditeur.
uses
sgcHTML_Component_Splitter;
var
oSplitter: TsgcHTMLComponent_Splitter;
begin
oSplitter := TsgcHTMLComponent_Splitter.Create(nil);
try
oSplitter.SplitterID := 'workspace';
oSplitter.Orientation := soHorizontal;
oSplitter.InitialSplit := 30;
oSplitter.MinSizeA := 180;
oSplitter.MinSizeB := 320;
oSplitter.GutterSize := 8;
oSplitter.Height := '560px';
oSplitter.PersistKey := 'workspace-split';
oSplitter.AddPaneA('<div class="p-3"><h5>Files</h5>...</div>');
oSplitter.AddPaneB('<div class="p-3"><h5>Editor</h5>...</div>');
WebModule.Response := oSplitter.HTML; // two panes + gutter + scoped CSS + drag script
finally
oSplitter.Free;
end;
end;
PersistKey mérite d'être mentionné : définissez-le, et la position de la poignée que déplace un visiteur est mémorisée côté client puis restaurée à sa prochaine visite, de sorte que la disposition d'un espace de travail reste stable d'une session à l'autre sans que vous ayez à écrire de code de gestion d'état.
Essayez-les
Les quatre sont livrés dans la version actuelle de sgcWebSockets, avec documentation complète, références des propriétés clés et exemples de code Delphi/C++Builder/.NET sur leurs propres pages : TreeGrid, PivotTable, ActivityFeed et Splitter. La matrice complète des fonctionnalités répertorie désormais 83 composants répartis en neuf familles — le prochain article de cette série couvre les nouveaux graphiques et codes visuels.
Des questions, des retours ou besoin d'aide pour une migration ? Contactez-nous — vous recevrez une réponse des personnes qui ont écrit le code.
