[0.9.31] StringGrid, filtre et optimisation
Bonsoir,
J'ai déjà partiellement abordé le sujet dans une autre discussion, mais je trouve le fonctionnement des StringGrids extrêmement lent... et j'essaye de le comprendre pour optimiser.
Je cherchais la meilleure méthode pour filtrer "visuellement" une StringGrid et d'une manière plus large pour les utiliser au mieux. Comme j'ai déjà rencontré récemment un problème de lenteur sur les tris de ce composant, j'ai fait quelques tests.
La StringGrid de référence que j'ai utilisée est une StringGrid par défaut modifiée ainsi :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var
Deb, Fin : TTime;
sTmp : string;
i : integer;
begin
Deb := now();
with SG1 do begin
RowCount := 10000;
for i:=1 to 9999 do
Cells[1,i] := intToStr(i);
end;
Fin := now();
Showmessage(TimeToStr(Fin-Deb)+' ( '+FloatTostr(Fin-Deb)+' )');
end; |
--> 00:00:00 (~4 x 10^-7)
J'ai utilisé 3 méthodes pour filtrer "visuellement" les nombres pairs.
Méthode 1 : Je parcours la SG1 et cache les lignes impaires :
Code:
1 2 3 4 5 6 7 8 9 10 11
| var
Deb, Fin : TTime;
i : integer;
begin
Deb := now();
with sg1 do
for i := 1 to RowCount -1 do
if i mod 2 <> 0 then RowHeights[i] := 0;
Fin := now();
Showmessage(TimeToStr(Fin-Deb)+' ( '+FloatTostr(Fin-Deb)+' )');
end; |
--> 00:00:03 (~441 x 10^-7). Et à l'utilisation, c'est en effet très "perceptible"...
Méthode 2: Je parcours SG1 et place les lignes paires dans une SG2 dont les propriétés sont définies par défaut dans l'IDE.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var
Deb, Fin : TTime;
i, iRow : integer;
begin
Deb := now();
iRow := 0;
with sg1 do
for i := 1 to RowCount -1 do
if i mod 2 = 0 then begin
iRow := iRow+1;
sg2.RowCount := iRow +1;
sg2.cells[1,iRow] := cells[1,i];
end;
Fin := now();
Showmessage(TimeToStr(Fin-Deb)+'('+FloatTostr(Fin-Deb)+')');
end; |
--> 00:00:03 (~462 x 10^-7)
Troisème méthode, identique à la seconde mais programmée différemment : le RowCount de SG2 n'est pas modifié 5000 fois mais défini une fois avant le traitement.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var
Deb, Fin : TTime;
iRow, i : integer;
begin
Deb := now();
sg2.RowCount := 5000;
iRow := 0;
with sg1 do
for i := 1 to RowCount -1 do
if i mod 2 = 0 then begin
iRow := iRow+1;
sg2.cells[1,iRow] := cells[1,i];
end;
Fin := now();
Showmessage(TimeToStr(Fin-Deb)+' ( '+FloatTostr(Fin-Deb)+' )');
end; |
--> 00:00:00 (~2 x 10^-7)
Si je peux éventuellement expliquer la différence entre la méthode 3 et la méthode 2 (la modification du RowCount donc l'ajout d'une ligne semble extrêmement lent*), pourquoi la méthode 1 est-elle si lente ? Entre les 2 méthodes également lentes et la plus rapide, il y a un facteur 200. Même si éventuellement on peut considérer que ce facteur n'est pas "significatif" et reste finalement acceptable, l'attente de l'utilisateur du résultat du filtre est désagréable... et donc s'il est possible de l'optimiser...
Bref, si vous avez de la documentation sur l'optimisation des StringGrids, je suis preneur... Cela m'évitera -même si c'est très intéressant et formateur- de m'engager dans des méthodes peu performantes.
Cordialement. Gilles
Rq : le code suivant est équivalent à la méthode 2
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var
Deb, Fin : TTime;
i : integer;
begin
Deb := now();
sg2.RowCount := 1;
with sg1 do
for i := 1 to RowCount -1 do
if i mod 2 = 0 then begin
sg2.RowCount := sg2.RowCount +1;
sg2.cells[1,sg2.RowCount -1] := cells[1,i];
end;
Fin := now();
Showmessage(TimeToStr(Fin-Deb)+'('+FloatTostr(Fin-Deb)+')');
end; |
--> 00:00:03 (~458 x 10^-7). C'est donc la permière utilisation de sg2.RowCount à chaque itération de la boucle qui ralentit le processus. Ensuite sa réutilisation, mémorisée, ne pénalise plus...