FAQ DelphiConsultez toutes les FAQ
Nombre d'auteurs : 124, nombre de questions : 933, dernière mise à jour : 28 septembre 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 remplir une grille avec le contenu d'une table ?
- Comment transformer un dataset en fichier texte ?
- Comment désactiver la demande de connexion à une base de données ?
- Comment filtrer le résultat d'un requête ou une table ?
- Comment mettre une date dans un filtre ?
- Comment définir un champ de référence ?
- Comment prédéfinir les colonnes d'une grille ?
- Comment connaître le nombre de lignes d'un ensemble de résultats avec RecordCount ?
- Comment remplacer le sablier par un autre curseur ?
- Comment accélérer les recherches dans ma base ?
- Comment vider une table ?
- Comment annuler l'opération en cours sur ma base ?
- Les éditions personnelles de Delphi permettent-elles d'accéder nativement aux bases de données ?
- Comment afficher dans un DBGrid un libellé provenant d'un autre dataset que le dataset en cours ?
- Comment insérer et récupérer un fichier dans un champ de type Blob ?
Les grilles non connectées (par opposition aux DBGrid) disposent souvent de plus de possibilités de manipulation : tris, dimensionnements des lignes, colorations, etc. Cette méthode peut donc vous être utile quand vous n'avez besoin que d'un accès en lecture au contenu d'une table ou d'une requête. De plus, une fois la grille remplie, vous pouvez réutiliser votre requête, par exemple pour réaliser d'autres actions.
Deux propriétés importantes des ensembles de données (TDataSet) sont utilisées dans le code ci-dessous :
- la propriété FieldCount, qui donne le nombre de colonnes nécessaires ;
- la propriété Fields, qui contient les données de l'enregistrement 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 23 24 25 26 27 28 29 30 31 | procedure TMyForm.Remplir; var ligne, colonne: Integer; begin with DataSet do begin Open; { Dimensionnement de la grille } MyStringGrid.RowCount := 2; MyStringGrid.ColCount := FieldCount; { Remplissage des entêtes } for colonne := 0 to MyStringGrid.ColCount - 1 do MyStringGrid.Cells[colonne, 0] := Fields[colonne].DisplayName; { Données } First; ligne := 1; while not Eof do begin for colonne := 0 to StringGrid1.ColCount-1 do MyStringGrid.Cells[colonne, ligne] := Fields[colonne].AsString; Next; Inc(ligne); if not Eof then MyStringGrid.RowCount := MyStringGrid.RowCount + 1; end; Close; end; end; |
Cette procédure prend en paramètre un dataset à exporter, le nom du fichier, le caractère séparant les zones et le caractère délimiteur des zones texte.
Les fichiers CSV ont ";" pour séparateur, les fichiers TSV ont la tabulation.
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 84 85 86 | procedure datasetToTextFile(ds : TDataSet; nomFichier : string; separateur : string = ';'; delimiteur : char = #0); var i : integer; fichier : TextFile; bm : TBookmark; sCursor : TCursor; valeur : string; openDS : boolean; begin try { Création du fichier de sortie } AssignFile(fichier,nomFichier); Rewrite(fichier); except on e: exception do raise Exception.Create('Erreur pendant la création du fichier [' + nomfichier + '] : ' + sLineBreak + e.message); end; sCursor := Screen.Cursor; Screen.Cursor := crHourGlass; try ds.DisableControls; openDS := not ds.Active; bm := nil; try with ds do begin if openDS then Open else begin { on sauvegarde la position de l'enregistrement courant dans } { le dataset afin de la restituer en fin de traitement } bm := ds.GetBookmark; First; end; { ligne d'en-tête : on met le nom des zones } for i:= 0 to FieldCount - 1 do begin if (i > 0) then write(fichier,separateur + ds.Fields[i].FieldName) else write(fichier,ds.Fields[i].FieldName); end; writeln(fichier); { passe à la ligne suivante dans le fichier } while not Eof do begin { écriture de chaque colonne de l'enregistrement courant } for i := 0 to FieldCount - 1 do begin { ajout du délimiteur si le champ est de type texte } if (delimiteur <> #0) and (Fields[i].DataType in [ftString, ftMemo, ftFmtMemo, ftFixedChar, ftWideString]) then valeur := AnsiQuotedStr(Fields[i].Text,delimiteur) else valeur := Fields[i].Text; { à partir du second champ, on ajoute le séparateur } if (i > 0) then write(fichier,separateur + valeur) else write(fichier,valeur) end; writeln(fichier); { passe à la ligne suivante dans le fichier } Next; end; { while not eof } end; { with ds } finally { si on a ouvert le ds, on le ferme } if openDS then ds.Close else { sinon, on se repositionne sur l'enregistrement initial } begin ds.GotoBookmark(bm); ds.FreeBookmark(bm); end; ds.EnableControls; CloseFile(fichier); end; finally Screen.Cursor := sCursor; end; end; |
Exemples :
Code delphi : | Sélectionner tout |
1 2 3 | datasetToTextFile(query1,'c:\temp\test1.csv'); datasetToTextFile(query1,'c:\temp\test2.csv',';','"'); datasetToTextFile(query1,'c:\temp\test3.csv',#9,''''); { #9 : tabulation } |
Lors d'une connexion à une base de donnée une fenêtre apparaît pour demander le nom d'utilisateur et le mot de passe. Ceci est le comportement par défaut de tous les composants de connexion à une base même si les informations de connexion sont correctement renseignées.
Tous les composants de connexion disposent d'un propriété LoginPrompt permettant de demander le login à l'utilisateur (TSQLConnection, TDCOMConnection, TDataBase, TAdoConnection, TIBDatabase, etc.). Il suffit de mettre cette propriété à faux pour désactiver cette demande.
On ne peut appliquer de requête sur le résultat d'une requête (à moins d'en copier le résultat dans une table intermédiaire, mais ce n'est pas je but ici) Par contre les composants descendant du TDataSet possèdent des fonctions de filtrage.
Filtrage Simple
Il suffit de mettre à jour le propriété Filter du DataSet et de mettre Filtered à True. Filter contient la condition d'affichage des champs. Par exemple pour ne conserver que les lignes dont le champ C2 est supérieur ou égal à 2 :
Code delphi : | Sélectionner tout |
1 2 | DataSet.Filter:='C2>=2'; DataSet.Filtered:=True; |
Filtrage sur évènement
Il est possible aussi d'utiliser l'évènement OnFilterRecord pour filtrer les enregistrements de la table. En reprenant l'exemple précédent le code serait le suivant :
Code delphi : | Sélectionner tout |
1 2 3 4 5 | procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean); begin Accept:=DataSet.FieldByName('C2').AsInteger>=2; end; |
Les dates dans les filtres doivent être comparées comme des chaînes, il faut donc mettre la date entre quotes pour la comparaison :
Code delphi : | Sélectionner tout |
Filter:='DateDebut=''12/01/04''';
Un champ de référence permet de proposer une liste de valeurs provenant ( référençant) d'une colonne d'une seconde table. La relation se faisant grâce à une clé primaire ou étrangère.
Pour définir un champ de référence il faut suivre les étapes suivantes :
- Double-cliquer sur le composant DataSet lié à la table
- Effectuer un click droit sur la liste puis Nouveau Champ
- Entrer un nom de champ avec son type.
- Mettre le type de champ sur référence
- Sélectionner l'ensemble de données contenant la référence ( liste de valeur )
- Choisir dans le champ clé le champ devant recevoir la référence
- Choisir dans clé de référence le champ de la table de référence qui doit être comparé au champ clé
- Choisir dans champ résultat la valeur du champ de référence quand champ clé = clé de référence
Une fois ceci effectué, la saisie dans une grille fait apparaître un ComboBox dans la cellule en cours d'édition afin de sélectionner la valeur dans la liste de référence.
Il existe deux méthodes principales pour définir les colonnes d'une grille avant que celle-ci ne soit liée à une table ouverte.
Méthode des champs persistants
Cette méthode est appelée ainsi car les champs du composant DataSet sont créés bien que la table ne soit pas ouverte. Pour définir les champs persistants il faut double-cliquer sur le DataSet voulu et ajouter les champs :
- Soit en ajoutant un champ en fonction de la table liée. Cette méthode est la plus simple mais impose que le composant DataSet puisse être connecté au serveur et que la table puisse être ouverte.
- Soit en ajoutant des nouveaux champs et en les définissants tels qu'ils le sont dans la table.
Une fois les champs définis, il suffit de cliquer dessus dans la liste et d'afficher l'éditeur de propriétés afin de modifier son affichage. L'ordre des champs dans la liste des champs définit l'ordre d'affichage dans une grille. Il est possible de modifier cet ordre simplement en glissant les champs à la bonne position dans la liste.
Cette méthode va fixer le nom et les caractéristiques des champs du DataSet en dur dans le programme, si un des champs défini dans la liste n'existe pas dans la table, une exception sera levée à l'ouverture de la table.
Méthode des colonnes prédéfinies
Cette méthode permet de modifier l'affichage de la grille sans modifier l'affichage des autres composants liée au DataSet. Il suffit de double-cliquer sur le DBGrid pour afficher la liste des colonnes. La propriété FieldName de la colonne permet de lier la colonne à un champ du DataSet.
Si un champ n'existe pas dans la table lié au DataSet dont dépend la grille, ceci ne provoque pas d'exception. De même si le type du champ n'est pas celui attendu.
La méthode recordCount permet de déterminer le nombre total d'enregistrements d'un ensemble de données. Attention cependant, cette propriété ne devrait être utilisée qu'avec des tables Paradox ou DBase. Signalons encore que si la propriété filter est utilisée, RecordCount ne retourne que 0 (si vide) et 1 (si non vide).
La méthode enregCount définie ci-dessous illustre une utilisation possible de la propriété RecordCount. enregCount le nombre de lignes de l'ensemble de résultats passé en paramètre sinon renvoie la valeur -1 en cas d'échec.
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 | ... Interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Db, StdCtrls, Grids, DBGrids, DBTables; function enregCount(dataset: TDataSet):longInt; overload; function enregCount(dataSource: TDataSource):longInt; overload; function enregCount(DBGrid: TDBGrid):longInt; overload; Implementation function enregCount(dataset: TDataSet):longInt; begin if assigned(dataSet) then if dataSet.Active then result := dataset.RecordCount else result := -1 else result := -1 end; function enregCount(dataSource: TDataSource):longInt; begin if assigned(dataSource) then result := enregCount(dataSource.DataSet) else result := -1; end; function enregCount(DBGrid: TDBGrid):longInt; begin if assigned(DBGrid) then result := enregCount(DBGrid.DataSource) else result := -1; end; ... |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | nb_enreg := enregCount(Query1); //ou nb_enreg := enregCount(Table1); // ou nb_enreg := enregCount(DataSource1); // ou nb_enreg := enregCount(DBGrid1); |
Remarque :
Etant donné les trops grandes restrictions pour utiliser de la propriété recordCount, nous préconisons l'utilisation de l'instruction SQL count.
Certains composants de connexion, en particulier TSQLConnection et TDatabase proposent la propriété SQLHourGlass, de type booléen, qui permet de spécifier si le curseur prend la forme du sablier jusqu'à ce que le serveur de base de données renvoie le résultat de la requête.
Pour les autres composants (TTable et TQuery), il faut explicitement recourir à un objet TSession pour accéder à cette propriété.
Ainsi, pour désactiver simplement l'affichage du sablier (le curseur devient le curseur par défaut : crArrow), il faut écrire :
Code delphi : | Sélectionner tout |
DataBase1.Session.SQLHourGlass := False; //accès à la session par défaut
Code delphi : | Sélectionner tout |
Table1.SessionName := MaSession;
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | procedure btnExecuteRequete(Sender : TObject); var Save_cuseur: TCursor; begin Save_curseur := screen.cursor; Screen.Cursor := XXX; // afficher le cuseur voulu try // Traitement finally Screen.Cursor := save_curseur; end; end; |
- crArrow : Flèche normale
- crCross : curseur en forme de croix
- crIBeam : curseur d'édition dans les grilles
- crHourGlass : curseur en forme de sablier
La liste des différents curseurs peut être trouvée en demandant l'aide sur TCursor.
Dans une application, les sources de données possèdent généralement des ensembles de données sous-jacents qui lui sont connectés à travers un DataSource. A partir de ce moment, ces ensembles de données réagissent à tout évènement qui se produit sur la source de données et en particulier sur l'évènement BeforeScroll. Ceci a pour avantage d'avoir des données toujours actualisées. Cependant, dans le cas de recherche (tri ou recherche incrémentale) dans la source, l'inconvénient sera de ralentir énormément la recherche (du fait du rafraîchissement constant des ensembles de données). À ce moment, il est nécessaire d'appeler la méthode DisableControls avant le début de la recherche et EnableControls juste après celle-ci.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 | Table1.DisablesControls; try // Opération de recherche ou de tri finally Table1.EnableControls; end; |
- En utilisant DELETE
L'instruction DELETE permet de supprimer tout ou partie des lignes d'une table. Pour supprimer la totalité des lignes d'une table on utilise la syntaxe suivante :
Code sql : Sélectionner tout Delete from NomDeTable;
- Sous Oracle l'instruction TRUNCATE permet également de supprimer toutes les lignes d'une table.
Cette instruction contient un commit implicite, il ne peut donc y avoir de RollBack après cette instruction.
Code sql : Sélectionner tout Truncate Table NomDeSchema.NomDeTable;
Code sql : Sélectionner tout 1
2Drop Table; Create Table(champ1 type1, champN typeN );
Vous ne pouvez pas tronquer une table si elle contient des contraintes d'intégrité référentielle. Vous devez désactiver les contraintes avant de tronquer la table. - Avec les tables Paradox/DBase sous le BDE il est possible d'utiliser TTable.EmptyTable. A la différence prêt que la table doit être ouverte en mode exclusif pour que cette opération fonctionne. Par contre la taille du fichier DB ou DBF est réellement réduit par cette opération, contrairement au autres opérations de suppression de tous les enregistrements.
Tous les descendants de TDataset possèdent des évènements qui nous permettent de contrôler l'état de l'opération en cours. Il s'agit des évènements Beforexxx. Par exemple, il existe un évènement BeforePost qui nous permet de faire un dernier test sur les données et décider si finalement celles-ci doivent êtres écrites dans la base de données ou non. Pour l'annulation, on utilise simplement la procédure abort :
Code delphi : | Sélectionner tout |
1 2 3 4 5 | procedure TForm1.Table1BeforePost(DataSet: TDataSet); begin if Table1Champ1.Value < 100 then abort; // Les données ne seront pas validées end; |
La version personnelle de Delphi ne fournit pas l'accès en natif à des composants pour les bases de données. Il est cependant possible d'y accéder à partir de composants tiers ou en attaquant directement l'API de la BDD en question ou encore par l'intermédiaire d'un autre langage.
Afin d'avoir un composant DBGrid qui affiche toutes les données d'une table plus un libellé en clair provenant d'une autre table, nous allons nous appuyer sur un clientDataSet.
Dans un premier temps, créez tous les champs de votre table de base. Ensuite ajoutez dans votre Dataset un nouveau champ (double clic sur le ClientDataSet, clic droit > Nouveau champ).
Les zones nom, type et taille du champ sont à remplir comme pour un champ classique. Ce qui va changer c'est la zone "Type de champ" : on va cocher ici Référence. Un champ référence fonctionne exactement comme un DBLookUpComboBox ; il affiche le libellé d'une autre table en se basant sur un index de la table en cours faisant le lien.
Description des champs | Définition de la référence |
Champs clé | C'est le champ dans la table en cours qui fera le lien vers l'autre table |
Ensemble de données | C'est la table contenant les libellés qu'on veut afficher |
Clés de référence | C'est le champ qui fera le lien avec « Champs clé » qu'on a choisi avant |
Champ résultat | C'est le champ libellé que l'on veut afficher dans notre DBGrid |
Cette QR prendra exemple avec les composants ADO mais elle est fonctionnelle avec n'importe quel composant de base de données.
Dans les exemples qui vont suivre, on considèrera que nous travaillons sur la structure de table suivante :
Code other : | Sélectionner tout |
1 2 3 | Id : Champ auto incrémenté Nom : Champ texte/varchar de 100 en taille Fichier : Champ Blob |
Il y a 2 méthodes pour insérer des documents (Images ,Documents Texte, programmes, etc.) dans une base de données :
- Par chargement
- Avec une requête
Code delphi : Sélectionner tout 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19if OpenDialog.execute then With AdoQuery do begin Close; SQL.Clear; SQL.add('insert into MaTable(Nom,Fichier)'); SQL.Add('Values(:PNom,:PFichier)'); ParamCheck := True; Parameters.ParamByName('PNom').Value := ExtractFileName(OpenDialog.Filename); Parameters.ParamByName('PFichier').LoadFromFile(OpenDialog.Filename, ftBlob); try ExecSQL; Except on E:Exception do begin Showmessage('Erreur lors de l''insertion de l''image dans la base de données : ' + E.Message); end; end; end;
- Avec une Table
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
21if OpenDialog.execute then With AdoTable do begin // Met la table en mode insertion de données Append; // enregistrement du nom de fichier dans la base de données FieldByName('Nom').asString := ExtractFileName(OpenDialog.Filename); // Enregistrement du fichier dans la base de données (FieldByName('Fichier') as TBlobField).LoadFromFile(OpenDialog.Filename, ftBlob); try // On ajoute dans la base de données Post; Except on E:Exception do begin // On annule la tentative d'ajout dans la base de données Cancel; Showmessage('Erreur lors de l''insertion de l''image dans la base de données : ' + E.Message); end; end; end;
- Avec une requête
- Par assignation
Cette méthode nécessite que l'on connaisse à l'avance le type de données que l'on va transmettre à la base de données.
Dans les deux exemples qui vont suivre, nous utiliserons des images.
- Avec une Requête
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
29var Img : TBitmap; begin if OpenDialog.execute then try img := TBitmap.Create; img.LoadFromFile(OpenDialog.FileName); With AdoQuery do begin Close; SQL.Clear; SQL.Add('insert into MaTable(Nom,Fichier)'); SQL.Add('Values(:PNom,:PFichier)'); ParamCheck := True; Parameters.ParamByName('PNom').Value := ExtractFileName(OpenDialog.Filename); Parameters.ParamByName('PFichier').Assign(Img); try ExecSQL; Except on E:Exception do begin Showmessage('Erreur lors de l''insertion de l''image dans la base de données : ' + E.Message); end; end; end; finally img.free; end; end;
- Avec une Table
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
31var Img : TBitmap; begin if OpenDialog.execute then try img := TBitmap.Create; img.LoadFromFile(OpenDialog.FileName); With AdoTable do begin // Met la table en mode insertion de données Append; // enregistrement du nom de fichier dans la base de données FieldByName('Nom').asString := ExtractFileName(OpenDialog.Filename); // Enregistrement du fichier dans la base de données FieldByName('Fichier').Assign(Img); try // On ajoute dans la base de données Post; Except on E:Exception do begin // On annule la tentative d'ajout dans la base de données Cancel; Showmessage('Erreur lors de l''insertion de l''image dans la base de données : ' + E.Message); end; end; end; finally img.free; end; end;
- Avec une Requête
B- La récupération
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | var sPath : String begin With AdoTable do begin // Récupération du nom du fichier sPath := ExtractFilePath(Application.ExeName) + FieldByName('Nom').AsString; // sauvegarde du fichier TBlobField(FieldByName('Fichier')).SaveToFile(sPath); 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.