IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 124, nombre de questions : 934, dernière mise à jour : 23 octobre 2024  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).

Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.

L'équipe Delphi de Developpez.com.

SommaireInterface utilisateurComposantsLe composant TStringGrid (18)
précédent sommaire suivant
 

Le composant StringGrid ne permet pas de supprimer une ligne directement avec son numéro. Il faut donc copier chaque ligne située après celle à supprimer sur la ligne qui la précède, puis supprimer la dernière ligne.
Par exemple, si on veut supprimer la ligne 3, on copie la 4 sur la 3, la 5 sur la 4, ... et on supprime la dernière.
On peut donc utiliser une procédure telle que :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
procedure RemoveLine(AStringGrid: TStringGrid; ALine: Integer); 
var 
  i: Integer; 
begin 
  for i := ALine to AStringGrid.RowCount - 2 do 
    AStringGrid.Rows[i] := AStringGrid.Rows[i + 1]; 
  AStringGrid.RowCount := AStringGrid.RowCount - 1; 
end;
On peut alors facilement supprimer la ligne 3 de la StringGrid "MaStringGrid" :
Code delphi : Sélectionner tout
RemoveLine(MaStringGrid,2);

Mis à jour le 13 octobre 2013 Smortex

Il suffit de rendre publiques les méthodes DeleteRow et DeleteColumn de la classe TCustomGrid dont hérite la classe TStringGrid à travers le transtypage de cette dernière en une classe dérivée déclarée dans la même unité :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
type TPublicStringGrid = class(TCustomGrid);  
...  
procedure TForm1.Button1Click(Sender: TObject);  
begin  
  //supprime la ligne n°2 (donc la troisième ligne, la première étant la ligne n°0) :  
  TPublicStringGrid(StringGrid1).DeleteRow(2);  
  
  //Supprime la deuxième colonne (colonne n°1) :  
  TPublicStringGrid(StringGrid1).DeleteColumn(1);  
end;

Mis à jour le 21 janvier 2014 LadyWasky

Le code suivant permet de centrer le texte dans les cellules d'un TStringGrid. Le centrage est à la fois vertical et horizontal. Le dessin est ici effectué avec l'API de Windows car la fonction TextOut du canevas des composants ne permet pas directement le centrage.

Code delphi : Sélectionner tout
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
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState); 
begin 
  With Sender As TStringGrid Do With Canvas Do 
  Begin 
    { Sélection de la couleur de fond } 
    If gdFixed in State 
      Then Brush.Color := clBtnFace 
      Else If gdSelected In State 
Then Brush.Color := clNavy 
Else Brush.Color := clWhite; 
  
    { Dessin du fond } 
    FillRect(Rect); 
  
    { Sélection de la couleur de texte } 
    If gdSelected In State Then 
      SetTextColor(Canvas.Handle,clWhite) 
    Else SetTextColor(Canvas.Handle,clBlack); 
  
    { Dessin du texte en utilisant la fonction API } 
    DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]), -1, Rect , 
      DT_CENTER or DT_NOPREFIX or DT_VCENTER or DT_SINGLELINE  ); 
  End; 
end;

Une variante de ce code permet d'écrire le texte d'une cellule sur plusieurs lignes :
Code delphi : Sélectionner tout
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
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState); 
begin 
  With Sender As TStringGrid Do With Canvas Do 
  Begin 
    { Sélection de la couleur de fond } 
    If gdFixed in State Then 
      Brush.Color := clBtnFace 
    Else If gdSelected In State Then 
    Brush.Color := clNavy 
  Else Brush.Color := clWhite; 
  
    { Dessin du fond } 
    FillRect(Rect); 
  
    { Sélection de la couleur de texte } 
    If gdSelected In State Then 
      SetTextColor(Canvas.Handle,clWhite) 
    Else SetTextColor(Canvas.Handle,clBlack); 
  
    { Dessin du texte en utilisant la fonction API } 
    DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]), -1, Rect , 
      DT_CENTER or DT_NOPREFIX or DT_WORDBREAK ); 
  End; 
end;

Mis à jour le 21 janvier 2014 Nono40

Lien MSDN : fonction DrawText

Ce code permet d'obtenir une grille avec des lignes de couleurs différentes. Ceci facilite la lecture des grilles de taille importantes. Pour utiliser ce code, il faut l'ajouter dans l'évènement OnDrawCell du TStringGrid :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState); 
begin 
  With Sender As TStringGrid Do With Canvas Do 
  Begin 
    { sélection de la couleur de fond } 
    If gdFixed in State 
      Then Brush.Color := clBtnFace 
      Else If gdSelected In State 
Then Brush.Color := clNavy 
Else If Odd(ARow) 
  Then Brush.Color := $FFE0FF 
  Else Brush.Color := $FFFFE0; 
    { Dessin du fond } 
    FillRect(Rect); 
    { Sélection de la couleur d'écriture } 
    If gdSelected In State 
      Then Font.Color:=clWhite 
      Else Font.Color:=clBlack; 
    { Dessin du texte } 
    TextOut(Rect.Left,Rect.Top,Cells[ACol,ARow]); 
  End; 
end;

Mis à jour le 13 octobre 2013 Nono40

Voici le code à appliquer pour mettre une image en fond des cellules blanches d'un TStringGrid. L'image est contenue dans une Bitmap, mais elle peut aussi être contenu dans un TImage. Cette procédure gère le déplacement du fond de l'image si l'utilisateur se sert des barres de défilement :

Code delphi : Sélectionner tout
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
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState); 
Var i,j,x,y:Integer; 
  R:TRect; 
begin 
  With Sender As TStringGrid Do With Canvas Do 
  Begin 
    If gdFixed in State Then 
    Begin 
      { Les cellules fixes sont toujours dessinées en gris } 
      Brush.Color := clBtnFace; 
      Brush.Style := bsSolid; 
      FillRect(Rect); 
    End 
    Else 
    Begin 
      If gdSelected In State Then 
      Begin 
{ Les cellules sélectionnées sont en bleue } 
Brush.Color := clNavy; 
Brush.Style := bsSolid; 
FillRect(Rect); 
      End 
      Else 
      Begin 
{ Recherche de la zone image à copier pour tenir compte des décalages } 
{ de la grille en fonction des barres de défilement. } 
X:=0; For i:=FixedCols+1 To ACol Do Inc(x,ColWidths [i]); 
Y:=0; For i:=FixedRows+1 To ARow Do Inc(Y,RowHeights[i]); 
R.Left   :=X; 
R.Right  :=X+Rect.Right-Rect.Left; 
R.Top    :=Y; 
R.Bottom :=Y+Rect.Bottom-Rect.Top; 
{ Dessin d'une partie de l'image } 
CopyRect(Rect,MonBitmap.Canvas,R); 
Brush.Style := bsClear; 
      End; 
    End; 
  
    { Sélection de la couleur de texte } 
    If gdSelected In State Then 
      SetTextColor(Canvas.Handle,clWhite) 
    Else SetTextColor(Canvas.Handle,clBlack); 
  
    { Dessin du texte en utilisant la fonction API } 
    DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]), -1, Rect ,DT_NOPREFIX ); 
  End; 
end;
MonBitMap est un objet de type TBitMap qui doit avoir été chargé avec l'image. L'image doit être suffisamment grande pour couvrir le fond du TStringGrid.

Mis à jour le 13 octobre 2013 Nono40

On a souvent besoin de trier le contenu d'un composant TStringGrid afin de présenter des données à l'utilisateur. Malheureusement, ce composant ne propose pas de fonction de tri. Voici donc un source démontrant comment implémenter cette fonctionnalité.

Mis à jour le 21 janvier 2014 Pierre Castelain

Voici une procédure qui vous permet d'exporter le contenu d'un TStringGrid vers Excel.

Code delphi : Sélectionner tout
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
procedure XlsWriteCellLabel(XlsStream: TStream; const ACol, ARow: Word; 
  const AValue: string); 
var 
  L: Word; 
const 
  {$J+} 
  CXlsLabel: array[0..5] of Word = ($204, 0, 0, 0, 0, 0); 
  {$J-}  
begin 
  L := Length(AValue); 
  CXlsLabel[1] := 8 + L; 
  CXlsLabel[2] := ARow; 
  CXlsLabel[3] := ACol; 
  CXlsLabel[5] := L; 
  XlsStream.WriteBuffer(CXlsLabel, SizeOf(CXlsLabel)); 
  XlsStream.WriteBuffer(Pointer(AValue)^, L); 
end; 
  
  
function SaveAsExcelFile(AGrid: TStringGrid; AFileName: string): Boolean; 
const 
  {$J+} CXlsBof: array[0..5] of Word = ($809, 8, 00, $10, 0, 0); {$J-} 
  CXlsEof: array[0..1] of Word = ($0A, 00); 
var 
  FStream: TFileStream; 
  I, J: Integer; 
begin 
  FStream := TFileStream.Create(PChar(AFileName), fmCreate or fmOpenWrite); 
  try  
    CXlsBof[4] := 0; 
    FStream.WriteBuffer(CXlsBof, SizeOf(CXlsBof)); 
    for i := 0 to AGrid.ColCount - 1 do 
      for j := 0 to AGrid.RowCount - 1 do  
        XlsWriteCellLabel(FStream, I, J, AGrid.cells[i, j]); 
    FStream.WriteBuffer(CXlsEof, SizeOf(CXlsEof));  
    Result := True; 
  finally 
    FStream.Free; 
  end; 
end;
Pour rappel, la directive $J contrôle si les constantes typées peuvent être modifiées ou non. Vous pouvez consulter l'aide sur cette directive dans l'aide pour plus de détails.

Utilisation :
Code delphi : Sélectionner tout
SaveAsExcelFile(StringGrid1,'c:\testxls.xls');

Mis à jour le 21 janvier 2014 Linkin

Pour cela, il faut activer l'option goAlwaysShowEditor et ajouter le code suivant dans l'événement OnKeyDown :

Code delphi : Sélectionner tout
1
2
3
4
5
6
procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word; 
  Shift: TShiftState); 
begin 
  if Key = VK_RETURN then 
    StringGrid1.Cells[StringGrid1.Col, StringGrid1.Row] := StringGrid1.Cells[StringGrid1.Col, StringGrid1.Row] + sLineBreak; 
end;
et dans l'événement OnDrawCell (issu de la faq Delphi):
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState); 
begin 
  with Sender as TStringGrid do with Canvas do 
  begin 
    { Sélection de la couleur de fond } 
    if gdFixed in State then 
      Brush.Color := clBtnFace 
    else if gdSelected in State then 
            Brush.Color := clNavy 
          else Brush.Color := clWhite; 
  
    { Dessin du fond } 
    FillRect(Rect); 
  
    { Sélection de la couleur de texte } 
    if gdSelected in State then 
      SetTextColor(Canvas.Handle,clWhite) 
    else SetTextColor(Canvas.Handle,clBlack); 
  
    { Dessin du texte en utilisant la fonction API } 
    DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]), -1, Rect ,DT_NOPREFIX or DT_WORDBREAK ); 
  end; 
end;

Mis à jour le 21 janvier 2014 rbag

Pour sélectionner du texte dans une cellule du composant TStringGrid, nous utilisons le composant TInplaceEdit spécialisé pour le traitement du texte des cellules des grilles. Il s'agit en réalité d'une fiche sans bordure dont le parent est la grille; c'est ce qui explique pourquoi il est invisible et n'apparaît pas en tant que contrôle indépendant.

Code delphi : Sélectionner tout
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
procedure TForm1.Button1Click(Sender: TObject);  
  
  //On parcours les contrôles enfants de la grille à la recherche du TInplaceEdit  
  function GetInPlaceEdit(ACustomGrid: TCustomGrid): TInplaceEdit;  
  var  
    i: integer;  
  begin  
    for i:=0 to ACustomGrid.ControlCount-1 do  
      if ACustomGrid.Controls[i] is TInplaceEdit then  
      begin  
        result:= TInplaceEdit(ACustomGrid.Controls[i]);  
        exit;  
      end;  
    result:= nil;  
  end;  
  
var  
  myRect: TGridRect;  
  ed: TInplaceEdit;  
begin  
  // Sélection de la cellule  
  myRect.Left := 1;  
  myRect.Top := 2;  
  myRect.Right := 1;  
  myRect.Bottom := 2;  
  sg.Selection := myRect;  
  
  // Donner le focus à la grille  
  ActiveControl:= sg;  
  
  // Passer la grille en mode édition  
  sg.EditorMode:= true;  
  
  // Récupérer l'éditeur  
  ed:= GetInPlaceEdit(sg);  
  // Et en faire quelque chose  
  // dans ce cas sélectionner le texte contenu dans la cellule  
  if ed <> nil then  
  begin  
    ed.SelStart:= 0;  
    ed.SelLength:= ed.GetTextLen;  
  end;  
end;
Remarque : TInPlaceEdit peut être utilisé avec tous les descendants de TCustomGrid, TDBGrid inclut bien évidemment.

Mis à jour le 21 janvier 2014 Pierre Castelain

Nous souhaitons que l'utilisateur n'ait pas la possibilité d'éditer certaines cellules d'un TStringGrid, les autres restant parfaitement éditables.

C'est la propriété Options-->goEditing qui permet ou non l'édition des cellules dans le TStringGrid.

Il suffit alors, dans l'évènement OnSelectCell, d'activer ou de désactiver l'option goEditing en fonction des coordonnées de la cellule et/ou de ce qu'elle contient :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,  
  ARow: Integer; var CanSelect: Boolean);  
begin  
  if (ARow=1)   //Condition à remplir pour interdire l'édition de la cellule  
  then StringGrid1.Options:=StringGrid1.Options-[goEditing] //désactive l'édition  
  else StringGrid1.Options:=StringGrid1.Options+[goEditing]; //active l'édition  
end;

Mis à jour le 21 janvier 2014 LadyWasky

Nous vous proposons ici deux procédures/fonctions toutes faites qui le permettent :

Première méthode (routines fichiers de bas niveau) :

Code delphi : Sélectionner tout
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
(* Sauver un TStringGrid dans un fichier *) 
procedure SaveStringGrid(StringGrid: TStringGrid; const FileName: TFileName); 
var f:    TextFile; 
    i, k: Integer; 
begin 
  AssignFile(f, FileName); 
  Rewrite(f); 
  with StringGrid do 
  begin 
    // Ecrire le nombre de Colonnes/lignes 
    Writeln(f, ColCount); 
    Writeln(f, RowCount); 
    // Boucler sur les cellules 
    for i := 0 to ColCount - 1 do 
      for k := 0 to RowCount - 1 do 
        Writeln(F, Cells[i, k]); 
  end; 
  CloseFile(F); 
end; 
  
// Charger un TStringGrid depuis un fichier 
// Attention, il faut tester l'existence du fichier avant d'utiliser cette procédure 
procedure LoadStringGrid(StringGrid: TStringGrid; const FileName: TFileName); 
var 
  f:          TextFile; 
  iTmp, i, k: Integer; 
  strTemp:    String; 
begin 
  AssignFile(f, FileName); 
  Reset(f); 
  with StringGrid do 
  begin 
    // Obtenir le nombre de colonnes 
    Readln(f, iTmp); 
    ColCount := iTmp; 
    // et de lignes 
    Readln(f, iTmp); 
    RowCount := iTmp; 
    // remplir les cellules 
    for i := 0 to ColCount - 1 do 
      for k := 0 to RowCount - 1 do 
      begin 
        Readln(f, strTemp); 
        Cells[i, k] := strTemp; 
      end; 
  end; 
  CloseFile(f); 
end;
Deuxième méthode (avec la classe TFileStream) :
Code delphi : Sélectionner tout
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
//écrire une chaîne de caractères depuis le flux 
procedure WriteStreamString(Stream : TStream; UneChaine : string); 
var LongueurChaine : integer; 
begin 
  //obtenir la longueur de la chaîne de caractères 
  LongueurChaine := Length(UneChaine); 
  //écrire cette longueur dans le flux 
  Stream.Write(LongueurChaine,SizeOf(integer)); 
  //écrire les caractères 
  Stream.Write(UneChaine[1], LongueurChaine); 
end; 
  
//retourne une chaîne de caractères depuis le flux 
function ReadStreamString(Stream : TStream) : string; 
var LongueurChaine : integer; 
begin 
  //obtenir la longueur de la chaîne de caractères 
  Stream.Read(LongueurChaine,SizeOf(integer)); 
  //Redimensionner la chaine pour allouer la mémoire nécessaire 
  SetLength(Result, LongueurChaine); 
  //Lire les caractères 
  Stream.Read(Result[1], LongueurChaine); 
end; 
  
// Sauver un TStringGrid dans un fichier 
procedure SaveStringGrid(StringGrid: TStringGrid; const FileName: TFileName); 
var f:TFileStream; 
    i, k ,cc, rr: Integer; 
begin 
  if FileExists(FileName) 
  then f:=TFileStream.Create(FileName,fmOpenWrite) 
  else f:=TFileStream.Create(FileName,fmCreate); 
  try 
    with StringGrid do 
    begin 
      cc:=ColCount; 
      rr:=RowCount; 
      // Ecrire le nombre de Colonnes/lignes 
      f.Write(cc,SizeOf(integer)); 
      f.Write(rr,SizeOf(integer)); 
      // Boucler sur les cellules 
      for i := 0 to ColCount - 1 do 
        for k := 0 to RowCount - 1 do 
          WriteStreamString(F,Cells[i, k]); 
    end; 
  finally 
     F.Free; 
  end; 
end; 
  
// Charger un TStringGrid depuis un fichier 
function LoadStringGrid(StringGrid: TStringGrid; const FileName: TFileName):boolean; 
var f:TFileStream; 
    iTmp, i, k, cc, rr: Integer; 
begin 
  result:=FileExists(FileName); 
  if not result then Exit; 
  f:=TFileStream.Create(FileName,fmOpenRead); 
  try 
    with StringGrid do 
    begin 
      // Obtenir le nombre de colonnes 
      f.Read(iTmp,SizeOf(integer)); 
      ColCount := iTmp; 
      // et de lignes 
      f.Read(iTmp,SizeOf(integer)); 
      RowCount := iTmp; 
      // remplir les cellules 
      for i := 0 to ColCount - 1 do 
        for k := 0 to RowCount - 1 do 
          Cells[i, k] := ReadStreamString(f); 
    end; 
  finally 
     F.Free; 
  end; 
end;

Mis à jour le 21 janvier 2014 LadyWasky

Il suffit de rendre publiques les méthodes MoveRow et MoveColumn de la classe TCustomGrid dont hérite la classe TStringGrid à travers le transtypage de cette dernière en une classe dérivée déclarée dans la même unité :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
type TPublicStringGrid = class(TCustomGrid);  
...  
procedure TForm1.Button1Click(Sender: TObject);  
begin  
  //Déplace la première ligne (Row=0) vers la seconde (Row=1) : 
  TPublicStringGrid(StringGrid1).MoveRow(0,1);  
  
  //Déplace la première colonne (Col=0) vers la seconde (Col=1) : 
  TPublicStringGrid(StringGrid1).MoveColumn(0,1); 
end;
Il est à noter que si les cellules vers lesquelles on déplace avec MoveRow ou MoveColumn ne sont pas vides, les valeurs seront permutées avec celles que l'on veut déplacer.

Mis à jour le 21 janvier 2014 LadyWasky Pedro

L'idée est de pouvoir tirer partie du fait que l'on puisse dessiner n'importe où sur le Canvas d'un StringGrid dans l'évènement OnDrawCell de ce dernier.
OnDrawCell ne fait rien d'autre que de nous fournir les coordonnées (ACol, ARow) de la cellule qui est prête à être dessinée, son rectangle de délimitation (Rect) et son Etat (State). Rien ne nous empêche de dessiner ce que l'on veut en dehors de la zone Rect qui nous est proposée…

Imaginons que nous souhaitons fusionner les cellules où

  • 1<=Colonne<=3
  • 2<=Ligne<=3

Nous dessinerons alors le texte de la cellule située ayant pour cordonnées (Colonne,Ligne)=(1,2) sur le rectangle s'étendant du coin supérieur gauche de la cellule (1,2) au coin inférieur droit de la cellule (3,3)

Le seul hic, c'est que si nous dessinons le texte de la cellule (1,2) dans cette zone, au moment où OnDrawCell est déclenché avec (ACol,Arow)=(1,2) dans cette nouvelle zone de dessin que nous avons choisie, Delphi re-préparera le dessin de fond des cellules (2,2), (2,3) etc.
Donc notre texte semblera coupé dans l'espace de la cellule supérieure gauche.

Le dessin de la cellule fusionnée doit donc se faire lorsque Delphi déclenche le OnDrawCell avec (ACol,Arow)=(3,3) (c'est-à-dire la cellule en bas à droite de notre zone fusionnée)

Voici une fonction, destinée à être appelée dans l'évènement OnDrawCell et qui utilise ce principe :
Code delphi : Sélectionner tout
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
function MergedCells(AStringGrid:TStringGrid; CurrentCol,CurrentRow,Col1,Row1,Col2,Row2:Integer; 
                    CurrentState: TGridDrawState):Boolean; 
var x1,y1,x2,y2:Integer; 
    ARect:TRect; 
begin 
  // Initialisations diverses 
  ARect:=Bounds(0,0,0,0); 
  x1:=Col1; 
  y1:=Row1; 
  x2:=Col2; 
  y2:=Row2; 
  result:=False; 
  
  // On vérifie que la zone fusionnée est valide 
  if x1 < 0 then x1:=0; 
  if x2 > AStringGrid.ColCount-1 then x2:=AStringGrid.ColCount-1; 
  if y1 < 0 then y1:=0; 
  if y2 > AStringGrid.RowCount-1 then y2:=AStringGrid.RowCount-1; 
  if (x1 > x2) or (y1 > y2) then 
  begin 
    result:=False; 
    Exit; 
  end; 
  
  // Si la cellule courante est la dernière de la zone de fusion, on dessine dans la fusion le texte de la cellule en haut à gauche 
  if ((CurrentCol=Col2) and (CurrentRow=Row2)) 
  then begin 
        ARect.Left:=AStringGrid.CellRect(Col1,Row1).Left; 
        ARect.Top:=AStringGrid.CellRect(Col1,Row1).Top; 
        ARect.Right:=AStringGrid.CellRect(Col2,Row2).Right; 
        ARect.bottom:=AStringGrid.CellRect(Col2,Row2).Bottom; 
        AStringGrid.Canvas.TextRect(ARect, ARect.Left+2, ARect.Top+2, AStringGrid.Cells[Col1,Row1]); 
       end; 
  // Si la cellule courante est dans la zone de fusion, on dit qu'on la dessiné (même si ce n'est pas vrai :) ) 
  if ((CurrentCol>=Col1) and (CurrentRow>=Row1) and (CurrentCol<=Col2) and (CurrentRow<=Row2)) 
  then result:=True; 
end;
Utilisation de la fonction
Code delphi : Sélectionner tout
1
2
MergedCells(AStringGrid:TStringGrid;CurrentCol,CurrentRow,Col1,Row1,Col2,Row2:Integer; 
                                          CurrentState: TGridDrawState):Boolean;
  • Elle s'utilise dans la méthode de l'évènement StringGrid1.OnDrawCell

Code delphi : Sélectionner tout
1
2
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState);
  • AStringGrid est le StringGrid concerné par la fusion de cellule, (StringGrid1 dans l'exemple qui suit…)
  • CurrentCol, CurrentRow, CurrentState sont les paramètres ACol, ARow et State fournis par l'évènement OnDrawCell
  • Col1, Row1 sont les coordonnées (Colonne, Ligne) de la cellule supérieure gauche
  • Col2, Row2 sont les coordonnées (Colonne, Ligne) de la cellule inférieure droite
  • Valeur renvoyée : True si la cellule à été prise en charge par la fusion (autrement dit si elle se trouve dans la zone définie par Col1,Row1, Col2 et Row2), sinon False

Exemple :
Dans un nouveau projet, sur notre fiche, nous avons juste mis un TStringGrid et ce code :
Code delphi : Sélectionner tout
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
unit Unit1; 
  
interface 
  
uses 
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, Grids; 
  
type 
  TForm1 = class(TForm) 
    StringGrid1: TStringGrid; 
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
      Rect: TRect; State: TGridDrawState); 
    procedure FormCreate(Sender: TObject); 
  private 
    { Déclarations privées } 
  public 
    { Déclarations publiques } 
  end; 
  
var 
  Form1: TForm1; 
  
implementation 
  
{$R *.dfm} 
  
function MergedCells(AStringGrid:TStringGrid;CurrentCol,CurrentRow,Col1,Row1,Col2,Row2:Integer;CurrentState: TGridDrawState):Boolean; 
var x1,y1,x2,y2:Integer; 
    ARect:TRect; 
begin 
  // Initialisations diverses 
  ARect:=Bounds(0,0,0,0); 
  x1:=Col1; 
  y1:=Row1; 
  x2:=Col2; 
  y2:=Row2; 
  result:=False; 
  
  // On vérifie que la zone fusionnée est valide 
  if x1 < 0 then x1:=0; 
  if x2 > AStringGrid.ColCount-1 then x2:=AStringGrid.ColCount-1; 
  if y1 < 0 then y1:=0; 
  if y2 > AStringGrid.RowCount-1 then y2:=AStringGrid.RowCount-1; 
  if (x1 > x2) or (y1 > y2) then 
  begin 
    result:=False; 
    Exit; 
  end; 
  
   // Si la cellule courante est la dernière de la zone de fusion, on dessine dans la fusion le texte de la cellule en haut à gauche 
  if ((CurrentCol=Col2) and (CurrentRow=Row2)) 
  then begin 
        ARect.Left:=AStringGrid.CellRect(Col1,Row1).Left; 
        ARect.Top:=AStringGrid.CellRect(Col1,Row1).Top; 
        ARect.Right:=AStringGrid.CellRect(Col2,Row2).Right; 
        ARect.bottom:=AStringGrid.CellRect(Col2,Row2).Bottom; 
        AStringGrid.Canvas.TextRect(ARect, ARect.Left+2, ARect.Top+2, AStringGrid.Cells[Col1,Row1]); 
       end; 
  // Si la cellule courante est dans la zone de fusion, on dit qu'on la dessiné (même si ce n'est pas vrai :) ) 
  if ((CurrentCol>=Col1) and (CurrentRow>=Row1) and (CurrentCol<=Col2) and (CurrentRow<=Row2)) 
  then result:=True; 
end; 
  
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState); 
begin 
     //On dessine la(les) cellule(s) 
     //d'abord on teste et on s'occupe des fusions de cellules 
    if not MergedCells(StringGrid1,ACol,ARow,2,2,2,3,State)then 
    if not MergedCells(StringGrid1,ACol,ARow,3,3,4,3,State)then 
     //puis si on a pas une cellule fusionnée on la dessine normalement 
    StringGrid1.Canvas.TextRect(Rect, Rect.Left+2, Rect.Top+2, StringGrid1.Cells[ACol,ARow]); 
end; 
  
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  Stringgrid1.Cells[1,1]:='Coucou'; 
  Stringgrid1.Cells[2,2]:='Salut'; 
  Stringgrid1.Cells[3,3]:='Bonjour à tout le monde'; 
end; 
  
end.
Ne pas oublier de lier :
Code delphi : Sélectionner tout
procedure TForm1.FormCreate(Sender: TObject);
à l'évènement Form1.OnCreate
Ainsi que :
Code delphi : Sélectionner tout
1
2
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; 
  Rect: TRect; State: TGridDrawState);
à l'évènement StringGrid11.OnDrawCell

Mis à jour le 21 janvier 2014 LadyWasky

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
//dans le formcreate  
  MaStringGrid.DoubleBuffered := True; 
  MaStringGrid.ControlStyle := StringGrid2.ControlStyle + [csClickEvents]; 
  
... 
  
// dans le ondrawcell du stringGrid 
// la condition peut etre un numero de colonne ou de ligne  
   if  maCondition Then 
     if (csClicked in (sender as TstringGrid).ControlState) Then 
       DrawFrameControl((sender as TstringGrid).Canvas.Handle, Rect,DFC_BUTTON, DFCS_BUTTONPUSH or DFCS_PUSHED ) 
     else 
       DrawFrameControl((sender as TstringGrid).Canvas.Handle, Rect, FC_BUTTON, DFCS_BUTTONPUSH )
Voilà, vous avez un joli bouton dans les cellules.

Mis à jour le 10 avril 2014 anapurna

Les méthodes BeginUpdate et EndUpdate n'existent pas pour les TStringGrids. Il existe seulement Grid.Rows[i].BeginUpdate et Grid.Rows[i].EndUpdate, pour le faire ligne par ligne.

Pour accélérer l'affichage des TStringGrids comportant un grand nombre de lignes, et aussi pour éviter le scintillement à l'affichage, on peut évidement utiliser BeginUpdate et EndUpdate par ligne.
Mais cette méthode est peu efficace. On peut donc utiliser la méthode suivante qui divise le temps d'affichage par 2 ou 3 :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{ ====================================================================== } 
procedure LockGrid(Grid: TStringGrid); 
//   Blocage de la mise à jour de l'affichage de la StringGrid 
begin 
  Grid.Perform(WM_SETREDRAW, 0, 0); 
end; 
{ ====================================================================== } 
procedure UnLockGrid(Grid: TStringGrid); 
//   Déblocage de la mise à jour de l'affichage de la StringGrid 
begin 
  Grid.Perform(WM_SETREDRAW, 1, 0); 
  Grid.Invalidate; 
end; 
{ ===================================================================== }

Utilisation :

Code Delphi : Sélectionner tout
1
2
3
  LockGrid(Grille) ;  // Blocage de l'affichage 
//  Remplissage de la grille ... 
  UnLockGrid(Grille) ;  // Déblocage de l'affichage

Testé avec D7 et D10.3

Mis à jour le 9 février 2019 Charly910

Avec ce code ...

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
var 
   I:integer; 
begin 
    // vide le composant 
    for i:=0 to StringGrid.RowCount -1 
    do StringGrid.rows[i].Clear; 
    // on met RowCount et éventuellement ColCount à leur valeur minimale = 1 
    StringGrid.RowCount:=1; 
    StringGrid.ColCount:=1;

Mis à jour le 4 avril 2019 patrice@

L'idée est de se déplacer dans une StringGrid avec les flèches droite et gauche parmi des colonnes dont le paramètre ColWidths=-1.
La valeur -1 permet d'avoir une colonne invisible.
Lorsqu'on se déplace avec les flèches, l'idée est de sauter les colonnes masquées. N'importe quelle colonne peut être masquée et il peut y avoir plusieurs colonnes masquées consécutives n'importe où (au début, au milieu, à la fin).
Dernière idée, si la première ou la dernière colonne est masquée, le focus doit rester sur la colonne la plus proche dont le paramètre ColWidths>0.

Pour résoudre le problème, il suffit de mettre le code dans la procédure KeyUp.

Code Delphi : Sélectionner tout
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
procedure TForm1.StringGrid1KeyUp(Sender: TObject; var Key: Word; 
  Shift: TShiftState); 
begin 
   if Key=VK_LEFT then 
   begin 
       if StringGrid1.ColWidths[StringGrid1.Col]<=0 
       then if StringGrid1.Col-1>=0 
            then begin 
                StringGrid1.Col:=StringGrid1.Col-1; 
            end; 
   end; 
  
   if Key=VK_RIGHT then 
   begin 
       if StringGrid1.ColWidths[StringGrid1.Col] <=0 
       then if StringGrid1.Col+1<=StringGrid1.ColCount-1 
            then begin 
                StringGrid1.Col:=StringGrid1.Col+1; 
            end; 
   end; 
  
   if (StringGrid1.ColWidths[StringGrid1.Col]<=-1) 
   and (StringGrid1.Col<StringGrid1.ColCount-1) 
   and (StringGrid1.Col>0) 
   then begin 
       StringGrid1KeyUp(Sender,Key,Shift); 
       Exit; 
   end; 
  
   if (StringGrid1.ColWidths[StringGrid1.Col]<=-1) 
   then begin 
       if (StringGrid1.Col=0) 
       then begin 
           Repeat 
              StringGrid1.Col:=StringGrid1.Col+1 
           Until StringGrid1.ColWidths[StringGrid1.Col]>0; 
       end; 
  
       if (StringGrid1.Col=StringGrid1.ColCount-1) 
       then begin 
           Repeat 
              StringGrid1.Col:=StringGrid1.Col-1 
           Until StringGrid1.ColWidths[StringGrid1.Col]>0; 
       end; 
  
   end; 
end;

Mis à jour le 6 février 2020 patrice@

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
type 
  TForm1 = class(TForm) 
    StringGrid1: TStringGrid; 
    procedure StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); 
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
    procedure FormShow(Sender: TObject); 
  private { Déclarations privées } 
    MyComboBox: TComboBox; 
    procedure MyComboBoxExit(Sender: TObject); 
  end;
Code Delphi : Sélectionner tout
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
procedure TForm1.MyComboBoxExit(Sender: TObject); 
begin 
  StringGrid1.Cells[StringGrid1.Col, StringGrid1.Row] := MyComboBox.Text; 
  MyComboBox.Visible := False; 
  StringGrid1.SetFocus; 
end; 
  
procedure TForm1.FormShow(Sender: TObject); 
begin 
  StringGrid1.Options := StringGrid1.Options + [goColSizing, goThumbTracking] - [goEditing]; 
  MyComboBox := TComboBox.Create(Self); 
  
  with MyComboBox do 
  begin 
    Parent := Form1; 
    Visible := False; 
    OnExit := MyComboBoxExit; 
  
    Items.Add('Delphi XE'); 
    Items.Add('Delphi XE2'); 
    Items.Add('Delphi XE3'); 
    Items.Add('Delphi XE4'); 
    Items.Add('Delphi XE5'); 
    Items.Add('Delphi XE6'); 
    Items.Add('Delphi XE7'); 
    Items.Add('Delphi XE8'); 
    Items.Add('Delphi 10 Seattle'); 
  end; 
end; 
  
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 
  FreeAndNil(MyComboBox) 
end; 
  
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; 
  var CanSelect: Boolean); 
var 
  R: TRect; 
begin 
  if (ACol > 0) and (ARow <> 0) then 
  begin 
    R := StringGrid1.CellRect(ACol, ARow); 
    R.Left := R.Left + StringGrid1.Left; 
    R.Right := R.Right + StringGrid1.Left; 
    R.Top := R.Top + StringGrid1.Top; 
    R.Bottom := R.Bottom + StringGrid1.Top; 
  
    with MyComboBox do 
    begin 
      Left := R.Left + 1; 
      Top := R.Top + 1; 
      Width := (R.Right + 1) - R.Left; 
      Height := (R.Bottom + 1) - R.Top; 
      Visible := True; 
    end; 
  
    if StringGrid1.Cells[ACol, ARow] <> EmptyStr then 
      MyComboBox.Text := StringGrid1.Cells[ACol, ARow] 
    else 
      MyComboBox.Text := EmptyStr; 
  
    MyComboBox.SetFocus; 
  end; 
  
  CanSelect := True; 
end;

Mis à jour le 28 septembre 2024 XeGregory

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.