Voir le flux RSS

Blog de Serge Girard (aka SergioMaster)

[FMX] Customiser une grille

Noter ce billet
par , 21/05/2019 à 11h41 (458 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
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 : 45
Taille : 7,5 Ko

Voilà donc mon premier code
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 : 45
Taille : 48,7 Ko
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 : 41
Taille : 3,8 Ko
Le TGlyph pouvant se rattacher à un TImageList j'en ai donc aussi rajouter un.
Un peu de code plus tard
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 : 41
Taille : 26,1 Ko

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

Envoyer le billet « [FMX] Customiser une grille » dans le blog Viadeo Envoyer le billet « [FMX] Customiser une grille » dans le blog Twitter Envoyer le billet « [FMX] Customiser une grille » dans le blog Google Envoyer le billet « [FMX] Customiser une grille » dans le blog Facebook Envoyer le billet « [FMX] Customiser une grille » dans le blog Digg Envoyer le billet « [FMX] Customiser une grille » dans le blog Delicious Envoyer le billet « [FMX] Customiser une grille » dans le blog MySpace Envoyer le billet « [FMX] Customiser une grille » dans le blog Yahoo

Mis à jour 27/05/2019 à 18h58 par SergioMaster (Quelques pas de plus)

Catégories
Delphi , FMX

Commentaires