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.
- Comment mettre une case à cocher dans un DBGrid ?
- Comment dessiner des lignes de couleur sur un DBGrid ?
- Comment gérer la sélection multiple sur un DBGrid ?
- Comment sélectionner une valeur dans une liste dans un DBGrid ?
- Comment afficher un DBMemo pour la saisie d'une cellule d'un DBGrid ?
- Comment trier le contenu d'un DBGrid ?
- Comment utiliser le composant DBLookUpComboBox ?
- Comment mettre une valeur par défaut dans un DBLookUpComboBox ?
- Comment mettre une valeur par défaut dans un DBComboBox ?
- Comment gérer la roulette de la souris sur un DBGrid ?
- Comment récupérer la ligne/colonne en cours sur un DBGrid ?
- Masquer l'ascenseur vertical/horizontal dans un DBGrid ?
- Comment lire directement l'image dans la base et l'afficher dans un TDBGrid ?
- Comment formater l'affichage d'un champ dans un DBGrid ?
- Comment détecter quel bouton d'un DBNavigator a été enfoncé ?
- Comment rendre une colonne d'un DBGrid en lecture seule ?
- Comment changer la couleur de toutes les lignes d'un DBGrid ?
- Comment modifier la hauteur d'une ligne dans un DBGrid ?
La case à cocher n'est pas prévue en standard dans la BDGrid, il faut donc la dessiner « à la main ». Le moyen le plus simple est d'utiliser deux images, une pour l'état « coché » et une pour l'état « décoché ».
Les images sont stockées dans une liste d'images imgCheck se trouvant dans un DataModule (DmImages). Dans cette liste d'images, on fixe arbitrairement l'image 0 comme étant l'image « décoché » et 1 comme étant l'image « coché ».
L'événement à intercepter pour dessiner la case à cocher est DrawColumnCell.
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 | procedure TForm1.dbGrid1DrawColumnCell( Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin if (column est une colonne 'case à cocher') then begin { on efface la cellule } dbGrid1.Canvas.FillRect(Rect); { si coché } if (column.Field a la valeur coché) then begin DmImages.imgCheck.draw(dbGrid1.Canvas, rect.Left + ((rect.Right - rect.Left - DmImages.imgCheck.Width) div 2), rect.Top, 1); end { sinon, pas coché } else begin DmImages.imgCheck.draw(dbGrid1.Canvas, rect.Left + ((rect.Right - rect.Left - DmImages.imgCheck.Width) div 2), rect.Top, 0); end end { si column ne correspond pas à une case à cocher, } { on ne s'occupe pas du dessin de la cellule, on } { transmet donc à DefaultDrawColumnCell } else begin dbGrid1.DefaultDrawColumnCell(rect,datacol,column,state); end; end; |
Remarques :
- le test if (column est une colonne 'case à cocher') est très variable : pour déterminer si la zone est une case à cocher, on peut se baser sur le type de la zone (if (Column.Field.DataType = ftBoolean) then...) ou bien sur son nom (if sameText(Column.FieldName,'nomZone') then...) ;
- le code ci-dessus peut servir à afficher autre chose qu'une case à cocher. Par exemple si une zone peut prendre 4 valeurs entières de 0 à 3, on peut avoir les 4 images équivalentes dans une liste d'images et l'utiliser ainsi :
Code delphi : | Sélectionner tout |
1 2 3 4 5 | dbGrid1.Canvas.FillRect(Rect); listeImages.draw(dbGrid1.Canvas, rect.Left + ((rect.Right - rect.Left - listeImages.Width) div 2), rect.Top, column.Field.AsInteger); |
Le code donné ci-dessus permet d'afficher la case à cocher, mais ne gère pas le cochage/décochage. Pour cocher ou décocher (i.e. pour changer l'image), il suffit de changer la valeur du champ. L'affichage sera mis à jour automatiquement.
Par exemple, voici comment cocher ou décocher sur un double-clic dans la grille :
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 | procedure TForm1.dbGrid1DblClick(Sender: TObject); begin with dbGrid1 do begin { La grille doit être modifiable... } if (not ReadOnly) { ainsi que le dataset } and DataSource.DataSet.CanModify { Et la zone sur laquelle on a cliqué doit } { être une case à cocher } and ((SelectedField.FieldName = 'UNE ZONE A COCHER') or (test sur un autre nom de zone) or ...) then begin DataSource.DataSet.Edit; SelectedField.AsBoolean := not SelectedField.AsBoolean; DataSource.DataSet.Post; end; end; end; |
Pour modifier le dessin du DBGrid, utiliser l'évènement OnDrawColumnCell. Il est possible de définir le dessin en fonction des donnée de la ligne en cours :
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 | procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin // si l'état de la cellule est sélectionné If gdSelected In State Then Begin // alors on la met de la couleur clNavy TDBGrid(Sender).Canvas.Brush.Color := clNavy End Else Begin // Sinon // Si le champ "indice" (champ exemple) de la ligne est à 1 If TDBGrid(Sender).DataSource.DataSet.FieldByName('Indice').Value=1 Then // alors on met la cellule de la ligne à clLime TDBGrid(Sender).Canvas.Brush.Color := clLime Else // Sinon on met la cellule à clWhite TDBGrid(Sender).Canvas.Brush.Color := clWhite; End; // On applique les modifications. TDBGrid(Sender).DefaultDrawColumnCell(rect,datacol,column,state); end; |
Pour permettre le MultiSelect d'un composant DBGrid il faut mettre à True les options suivantes du composant : dgRowSelect et dgMultiSelect. Il est ensuite possible de sélectionner plusieurs lignes avec CTRL-Click.
Pour traiter les lignes sélectionnées la propriété SelectedRow permet de se positionner sur les enregistrement correspondants :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | procedure TForm1.Button4Click(Sender: TObject); Var i:Integer; begin Memo1.Clear; With DBGrid1 Do Begin for i:=0 to SelectedRows.Count-1 do begin DataSource.DataSet.GotoBookmark(pointer(SelectedRows.Items[i])); Memo1.Lines.Add(DataSource.DataSet.FieldByName('UnChamp').AsString); End; End; end; |
Cette fonction est directement intégrée dans le TDBGrid, il s'agit d'utiliser les propriétés PickList des colonnes.
À la conception :
Double-cliquer sur la grille pour afficher les colonnes, puis remplir la propriété PickList la colonne voulue.
À l'exécution :
Utiliser la propriété Columns du DBGrid pour ajouter les valeurs :
Code delphi : | Sélectionner tout |
DBGrid1.Columns[0].PickList.Add('UneValeur');
Le DBMemo sera affiché lors de la saisie d'un champ d'une DBGrid par un double-clic sur la cellule ou l'appui sur le bouton '...'.
En premier lieu pour afficher le bouton '...' dans la cellule il faut mettre à cbsEllipsis la propriété ButtonStyle de la colonne.
Ensuite il faut renseigner les évènements OnEditButtonClick et OnDrawColumnCell de la grille :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | procedure TForm1.DBGrid1EditButtonClick(Sender: TObject); begin With DbMemo1 Do Begin Visible:=True; SetFocus; End; end; procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin If (gdSelected In State)And(DataCol=1) Then Begin DBMemo1.Left:= DBGrid1.Left+Rect.Left; DBMemo1.Top := DBGrid1.Top +Rect.Top; End; end; |
Code delphi : | Sélectionner tout |
DBMemo1.Visible:=False;
Il n'est pas possible de trier les données directement dans le DBGrid. Le tri doit être effectué au niveau du TDataSet lié à la grille. Deux solutions possible :
- Créer un index correspondant au tri voulu et utiliser cet index pour l'ouverture de la table.
- Ajouter une clause ORDER BY dans le cas d'une requête.
À noter que la création d'un index peut aussi améliorer les performance d'un ORDER BY.
Ce composant permet de remplir un champ d'une table en sélectionnant cette valeur dans une colonne d'un autre ensemble de données.
Pour réaliser cette fonction vous devez renseigner les propriétés suivantes :
- DataSource : source de donnée de la table contenant le champ à remplir
- DataField : nom du champ lié à la table
- ListeSource : source de données donnant la liste des valeur possibles
- KeyField : nom du champ de la liste de référence qui doit être mis en correspondance avec DataField
- ListField : Liste des champs affichés dans la liste déroulante. Il est possible d'afficher plusieurs champs en les séparant par des ';'. Si cette propriété n'est pas renseignée, c'est KeyField qui sera affiché dans la liste déroulante.
À noter que si les valeurs de la liste du DBLookUpComboBox sont fixes et non liées à une table, c'est le composant DBComboBox qu'il faut utiliser.
Pour cela il faut fixer la valeur du champ de la table juste après l'insertion d'un nouvel enregistrement. Ceci en positionnant la table de référence (liste de valeur de la DBLookUpComboBox) sur l'enregistrement voulu.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 | procedure TForm1.Table1NewRecord(DataSet: TDataSet); begin With DBLookUpComboBox1 Do Begin ListSource.DataSet.First ; Field.Value := ListSource.DataSet.FieldByName(KeyField).Value; End; end; |
Pour cela il faut fixer la valeur du champ de la table juste après l'insertion d'un nouvel enregistrement. Ceci en utilisant la première valeur de la liste.
L'exemple donné ici affecte par défaut le premier élément de la liste :
Code delphi : | Sélectionner tout |
1 2 3 4 5 | procedure TForm1.Table1NewRecord(DataSet: TDataSet); begin With DBComboBox1 Do If Items.Count>0 Then Field.Value := Items[0]; end; |
La roulette n'est pas gérée correctement par défaut dans le composant DBGrid. Pour qu'elle soit prise en compte il faut suivre la méthode suivante, elle est basée sur la dérivation de la méthode WindowProc de la grille afin de gérer le message WM_MOUSEWHEEL.
Dans la déclaration de la fiche, ajouter :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | type TForm1 = class(TForm) DBGrid1 : TDBGrid; ... private { Déclarations privées } OldWindowProc: TWndMethod; Procedure DBGridNewWindowProc(var Msg: TMessage); ... End; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | procedure TForm1.FormCreate(Sender: TObject); begin // Sauvegarde la WndProc actuelle du DBGrid1. OldWindowProc := DBGrid1.WindowProc; // Affecte une nouvelle procédure de fenêtre. DBGrid1.WindowProc := DBGridNewWindowProc; end; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | procedure TForm1.DBGridNewWindowProc(var Msg: TMessage); begin //.Interception de l'évènement WM_MOUSEWHEEL. if Msg.Msg = WM_MOUSEWHEEL then begin if (DBGrid1.DataSource.DataSet.Active) then begin if SmallInt(Msg.WParamHi) < 0 then DBGrid1.DataSource.DataSet.Next else DBGrid1.DataSource.DataSet.Prior; end; Exit; end; //.Traitement normal des autres message. OldWindowProc(Msg); end; |
Les propriétés Row et Col ne sont pas publiées dans le composant DBGrid, il est possible d'y accéder en transtypant la grille comme suit :
Code delphi : | Sélectionner tout |
1 2 | Ligne := TDrawGrid(DBGRID1).Row; Colonne := TDrawGrid(DBGRID1).Col; |
La fonction, ShowScrollBar, spécifique à Windows (il faut donc inclure l'unité Windows) doit être utilisé pour effectuer cette opération; ainsi :
Code delphi : | Sélectionner tout |
1 2 3 | ShowScrollBar(DBGrid1.Handle, SB_BOTH, False); ShowScrollBar(DBGrid1.Handle, SB_HORZ, False); ShowScrollBar(DBGrid1.Handle, SB_VERT, False); |
Il faut utiliser l'évènement OnDrawColumnCell du TDBGrid.
La première chose est de vérifier le type du champ, à l'aide du paramètre Column de cet évènement qui
représente la colonne qui doit être dessinée, puis recupérer les données de l'image.
Les blobs sont en réalité constituées de deux parties :
- une en-tête sur 8 bits (description de l'image : hauteur, largeur etc.)
- les données
Pour réaliser l'exemple, vous pouvez vous servir de la table "animals" de la base "DBDEMOS" livrée avec Delphi (ici Delphi 7).
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 | procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); var tmp : TBitmap; stream : TMemoryStream; begin if(Column.Field.IsBlob) then begin stream := TMemoryStream.Create(); tmp := TBitmap.Create(); try TGraphicField(Column.Field).SaveToStream(stream); stream.SetSize(stream.Size - 8); //On retire l'en-tête du blob, on récupère uniquement les données stream.Seek(int64(8), soFromBeginning); //on se place au début des données tmp.LoadFromStream(stream); DBGrid1.Canvas.CopyRect(Rect, tmp.Canvas, tmp.Canvas.ClipRect); finally tmp.Free; stream.Free; end; end else DBGrid1.DefaultDrawDataCell(Rect, Column.Field, State); end; |
Pour la mise en forme d'un champ dans un DBGrid, il faut ajouter du code dans l'événement OnDrawColumCell de celui-ci. Il faut par ailleurs penser à mettre la propriété DefaultDrawing à False pour que le code de l'événement soit exécuté.
L'événement OnDrawColumCell est appelé chaque fois qu'une cellule doit être dessinée, les paramètres Column et State nous permettent respectivement de connaître la colonne qui est en train d'être redessinée et l'état de la cellule (cellule fixe, cellule sélectionnée…).
Le code suivant est un exemple qui nous permet de mettre la première colonne en gras et en bleu, et la seconde en gras et en vert.
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.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin with DBGrid1.Canvas do begin //On teste la colonne case Column.Index of 0: begin //On change la police Font.Style := [fsBold]; Font.Color := clBlue; end; 1: begin //On change la police Font.Style := [fsBold]; Font.Color := clLime; end; end; //On écrit le texte TextOut(Rect.Left, Rect.Top, DBGrid1.Fields[DataCol].Text); end; end; |
Une solution simple est d'utiliser l'évènement OnClick du TDBNavigator :
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 | procedure TForm1.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn); var BtnName: string; begin case Button of nbFirst : BtnName := 'nbFirst'; nbPrior : BtnName := 'nbPrior'; nbNext : BtnName := 'nbNext'; nbLast : BtnName := 'nbLast'; nbInsert : BtnName := 'nbInsert'; nbDelete : BtnName := 'nbDelete'; nbEdit : BtnName := 'nbEdit'; nbPost : BtnName := 'nbPost'; nbCancel : BtnName := 'nbCancel'; nbRefresh: BtnName := 'nbRefresh'; end; MessageDlg('Le bouton ' + BtnName + ' a été cliqué.', mtInformation, [mbOK], 0); end; |
On a la possibilité de rendre la colonne d'une DbGrid ReadOnly en exploitant l'évènement AfterScroll de notre dataset.
L'exemple ci-dessous met la quatrième colonne en lecture seule :
Code delphi : | Sélectionner tout |
1 2 3 4 | procedure TForm1.Table1AfterScroll(DataSet: TDataSet); begin DbGrid1.Columns[3].ReadOnly := True; end; |
Il peut arriver qu'on ait besoin de donner une couleur particulière à toutes les lignes d'un DBGrid.
Il convient de rappeler que pour pouvoir sélectionner plusieurs lignes, il est nécessaire de passer à true l'option dgMultiSelect de notre DBGrid.
Nous allons exploiter l'évènement OnDrawColumnCell et la propriété SelectedRows.CurrentRowSelected.
Cette dernière est de type booléen renvoyant true si la ligne en cours de dessin est sélectionnée.
Voici un exemple d'utilisation :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | procedure Tform1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin If DBGrid1.SelectedRows.CurrentRowSelected then Begin DBGrid1.Canvas.Brush.Color := clSkyBlue; // <- Couleur fond de ligne Column.Grid.DefaultDrawColumnCell(Rect, DataCol, Column, State); end; end; |
Admettons que l'on souhaite adapter la hauteur des lignes d'un TDBGrid en fonction de la taille du texte des cellules.
- Il faut pouvoir modifier la hauteur d'une ligne d'un TDBGrid, pour ce faire, il faut accéder à la propriété protégée RowHeiths (voir Comment accéder aux Méthodes "Protected" d'une classe ?)
Code delphi : Sélectionner tout 1
2
3
4
5
6
7
8
9
10type TPublicCustomGrid=class(TCustomGrid); ... begin //change la hauteur de la 11ème ligne //(la première ligne étant la numéro 0 (ligne de titre)) TPublicCustomGrid(DBGrid1).RowHeights[10]:=50; //Change la hauteur du titre TPublicCustomGrid(DBGrid1).RowHeights[0]:=50; end;
- Ensuite Il faut connaître la hauteur d'un texte, en pixels comme cela est expliqué dans cette QR.
- Enfin il faut savoir, dans l'évènement OnDrawDataCell, à quel numéro de ligne on se trouve :
Code delphi : Sélectionner tout 1
2
3
4
5
6
7
8type TPublicCustomGrid=class(TCustomGrid); procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState); var numLigne:integer; begin //ajouter +1 à cause de la ligne d'en-têtes de colonnes (nom des champs) Numligne:=DBGrid1.DataSource.DataSet.RecNo+1; end;
- Et puis combiner le tout :
Code delphi : Sélectionner tout 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15type TPublicCustomGrid=class(TCustomGrid); procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState); var NumLigne:Integer; UnTexte:string; Taille:TPoint; HauteurActuelle:Integer; begin UnTexte:=Field.DisplayText; Taille:=TextSize(UnTexte,DBGrid1.Font); NumLigne:=DBGrid1.DataSource.DataSet.RecNo+1; HauteurActuelle:=TPublicCustomGrid(DBGrid1).RowHeights[NumLigne]; if Taille.Y>HauteurActuelle then TPublicCustomGrid(DBGrid1).RowHeights[NumLigne]:=Taille.Y; end;
- Par contre, en récupérant le numéro de ligne avec RecNo, cela ne fonctionne pas si la Table ou la TQuery est filtrée.
Pour palier à cet inconvénient, il faut pouvoir récupérer l'objet DataLink (propriété protected de type TDataLink) du DBGrid, la propriété ActiveRecord de cet objet nous donnera le numéro de ligne, à coup sûr, sur laquelle on se trouve au moment du dessin dans l'évènement OnDrawDataCell. - Et finalement le code final sera :
Code delphi : Sélectionner tout 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20type TPublicCustomGrid=class(TCustomGrid); procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState); var NumLigne:Integer; UnTexte:string; Taille:TPoint; HauteurActuelle:Integer; begin UnTexte:=Field.DisplayText; Taille:=TextSize(UnTexte,DBGrid1.Font); With TPublicCustomGrid(DBGrid1) do begin NumLigne:=FDataLink.ActiveRecord+1; HauteurActuelle:=RowHeights[NumLigne]; if Taille.Y>HauteurActuelle then RowHeights[NumLigne]:=Taille.Y; end; end;
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 çaLes 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.