par , 21/05/2019 à 10h41 (1165 Affichages)
Suite à cette discussion sur la dérivation d'un TGrid initiée par Selzig plusieurs idées se sont bousculées dans ma caboche. Idées que je développerai certainement dans mon blog mais, en attendant voici quelques approches.
Tout d'abord je me suis posé la question "est-il possible de créer les liens à l'exécution ?" J'ai vu à ce moment de mes recherches une vidéo brésilienne (qu'il va me falloir retrouver) qui faisait une démonstration de cette possibilité mais avec une StringGrid donc oui, c'était possible.
Solution simple, après avoir fait une liaison rapide j'ai regardé le source du dfm et, en quelques lignes
1 2 3 4 5 6
| with TLinkGridToDataSource.Create(Self) do
begin
GridControl:=Grid1;
DataSource:=BindSourceDB1;
Active:=True;
end; |
J'ai obtenu un premier truc fonctionnel équivalent à une liaison rapide.
Fonctionnel, oui mais loin d'être top je me suis ensuite mis en tête d'utiliser une liaison manuelle. Tout de suite, la chose s'est compliquée
après avoir, à mon habitude, tout d'abord établi les infos via le composant TBindingsList, ouvert le dfm pour récupérer les informations l'affichage restait vide
jusqu'à ce que je comprenne qu'il me fallait aussi créer les colonnes !
![Nom : Capture_1.PNG
Affichages : 239
Taille : 7,5 Ko](https://www.developpez.net/forums/attachment.php?attachmentid=475981&d=1558171325)
Voilà donc mon premier code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
FLinkToGrid:=TBindGridLink.Create(Self);
with FLinkToGrid do
begin
ControlComponent := Grid1;
SourceComponent := BindSourceDB1;
// positionnement
with PosControlExpressions.AddExpression
do begin
ControlExpression := 'Selected';
SourceExpression := 'Math_Max(0,DBUtils_ActiveRecord(Self))';
end;
with PosSourceExpressions.AddExpression do
begin
ControlExpression := 'Math_Max(1,Selected+1)';
SourceExpression := 'DBUtils_ValidRecNo(Self)';
end;
// colonnes
for I := 0 to FDQuery1.Fields.Count-1 do
begin
AColumn:=TColumn.Create(Grid1);
AColumn.Name:=FDQuery1.Fields[i].FieldName;
AColumn.Header:=FDQuery1.Fields[i].FieldName;
Grid1.AddObject(AColumn);
with ColumnExpressions.AddExpression do
begin
ColumnName := FDQuery1.Fields[i].FieldName;;
ColumnIndex := i;
SourceMemberName := FDQuery1.Fields[i].FieldName;
with FormatCellExpressions.AddExpression do
begin
ControlExpression := 'Data';
SourceExpression := 'Value';
end;
end;
Active:=True;
end; |
Néanmoins restait encore des choses à explorer : les dates ne s'affichaient pas
il fallait donc encore affiner ! Bêtement je croyais que TColumn était une classe générique qui reconnait donc le type de données, hélas non. Il me fallait selon le type de données créer les colonnes adéquates.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
procedure TForm41.btnExecSQlClick(Sender: TObject);
begin
FDQuery1.Close;
FDQuery1.SQL.Text:=Memo1.Lines.Text;
FDQuery1.Open;
BuildLinks;
end;
procedure TForm41.BuildLinks;
var i : Integer;
AColumn : TColumn;
ADateCol : TDateColumn;
AFloatCol : TFloatColumn;
Expr : String;
begin
// if Assigned(FGridLink) then
// begin
// FGridLink.Active:=False;
// FreeAndNil(FGridLink);
// end;
//
// FGridLink:=TLinkGridToDataSource.Create(Self);
// FGridLink.GridControl:=Grid2;
// FGridLink.DataSource:=BindSourceDB1;
// FGridLink.Active:=True;
if Assigned(FLinkToGrid) then
begin
FLinkToGrid.Active:=False;
Grid1.ClearColumns;
FreeAndNil(FLinkToGrid);
end;
FLinkToGrid:=TBindGridLink.Create(Self);
with FLinkToGrid do
begin
ControlComponent := Grid1;
SourceComponent := BindSourceDB1;
with PosControlExpressions.AddExpression
do begin
ControlExpression := 'Selected';
SourceExpression := 'Math_Max(0,DBUtils_ActiveRecord(Self))';
end;
with PosSourceExpressions.AddExpression do
begin
ControlExpression := 'Math_Max(1,Selected+1)';
SourceExpression := 'DBUtils_ValidRecNo(Self)';
end;
for I := 0 to FDQuery1.Fields.Count-1 do
begin
case FDQuery1.FieldDefs[i].DataType of
// Date
TFieldType.ftDate,
TFieldType.ftDateTime,
TFieldType.ftTimeStamp : begin
ADateCol:=TDateColumn.Create(Grid1);
ADateCol.Format:='dd/mm/yy';
AColumn:=TColumn(ADateCol);
Expr:='DisplayText';
end;
// Numériques
TFieldType.ftCurrency,
TFieldType.ftFloat,
TFieldType.ftFMTBcd : begin
AFloatCol:=TFloatColumn.Create(Grid1);
AFloatCol.DecimalDigits:=2;
Expr:='Text';
AColumn:=TColumn(AFloatCol);
end;
else begin
// Autre (défaut)
AColumn:=TColumn.Create(Grid1);
Expr:='Value';
end;
end;
AColumn.Name:=FDQuery1.Fields[i].FieldName;
AColumn.Header:=FDQuery1.Fields[i].FieldName;
Grid1.AddObject(AColumn);
with ColumnExpressions.AddExpression do
begin
ColumnName := FDQuery1.Fields[i].FieldName;;
ColumnIndex := i;
SourceMemberName := FDQuery1.Fields[i].FieldName;
with FormatCellExpressions.AddExpression do
begin
ControlExpression := 'Data';
if FDQuery1.FieldDefs[i].DataType=TFieldType.ftDate
then SourceExpression :='FormatDateTime(''dd/mm/yy'',value)'
else SourceExpression := Expr;
end;
end;
end;
Active:=True;
end;
end; |
et voilà le résultat
![Nom : Capture_2.PNG
Affichages : 292
Taille : 48,7 Ko](https://www.developpez.net/forums/attachment.php?attachmentid=475983&d=1558171977)
Bien sûr, il y a encore de nombreux types de champs et donc types de colonnes à créer, de même que, pour l'instant, ma grille n'est qu'en lecture seule (il m'aurait fallu ajouter des ParseExpressions pour qu'il en soit autrement) mais l'idée générale est là.
Un autre point avait été soulevé : mettre une icône dans les entêtes de colonnes, objectif mettre une indication de tri. C'est une autre vidéo (
) qui m'a mis sur une première piste à savoir, comment accéder à chaque entête de colonne. Il m'a ensuite fallu pas mal de recherche pour la suite. Voici une solution qui s'appuie sur les styles
tout d'abord j'ai posé un StyleBook sur ma forme et modifié le HeaderItemStyle en lui adjoignant un TGlyph
![Nom : Capture_3.PNG
Affichages : 235
Taille : 3,8 Ko](https://www.developpez.net/forums/attachment.php?attachmentid=475986&d=1558172835)
Le TGlyph pouvant se rattacher à un TImageList j'en ai donc aussi rajouter un.
Un peu de code plus tard
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| procedure TForm41.FormCreate(Sender: TObject);
begin
Grid1.OnApplyStyleLookup:=GridApplyStyleLookup;
end;
procedure TForm41.GridApplyStyleLookup(Sender: TObject);
var H : THeader;
HI : THeaderItem;
G : TGlyph;
i : Integer;
begin
if Grid1.FindStyleResource<THeader>('Header',H) then
begin
H.Height:=40;
for I := 0 to H.Count-1 do
begin
HI:=H.Items[i];
if HI.FindStyleResource<TGlyph>('Glyph1Style',G) then
begin
G.Visible:=True;
if odd(i) then G.ImageIndex:=0 else G.ImageIndex:=1;
end;
end;
end;
end; |
Voici une illustration de ce qui peut se faire
![Nom : Capture.PNG
Affichages : 215
Taille : 26,1 Ko](https://www.developpez.net/forums/attachment.php?attachmentid=475987&d=1558172998)
Bien évidemment je suis encore loin de l'indication du tri néanmoins j'ai déjà une petite idée, à base de Tag, qui reste à germer.
Mise à jour du 27/05
Une petite vidéo pour montrer mes avancées
https://serge-girard.developpez.com/...ridheader.webm
Toujours à base de liste d'images mais j'étudie sérieusement l'utilisation d'un TPath voire d'un TPathLabel (le seul hic il faut jouer sur la rotation de la flèche au lieu d'un simple index d'image) . Cette étude poussée de TPath m'a conduit à proposer en téléchargement un petit programme et ses sources à cette adresse
Mes prochains pas me porteront vers la dérivation de la classe TColumn, à moins que ce soit un helper ou une interface. Affaire à suivre
Surtout n'hésitez pas à me faire part d'autres pistes