1. Introduction

Les pré requis pour ce tutorial sont : Savoir créer et sauvegarder un projet, la connaissance des composants TButton, TEdit, TMaskEdit, TPanel, et TMainMenu, la classe AnsiString, avoir entendu parler de base de donnée et si possible en avoir utilisé.

Il est nécessaire d'avoir le BDE d'installé (pour Delphi 5, il faut donc la version professionnelle minimum ...)


Dans ce tutorial, je n'utiliserais pas les contrôles visuels orientés "Base de données" comme les TDBEdit, TDBMemo, TDBNavigator etc ... Néanmoins j'y ai placé un TDBGrid mais en lecture seule, qui ne sert qu'à visualiser les opérations que je fait sur la table. Le but de ce tutorial est de voir comment on manipule par du code pascal une base de donnée, par l'intermédiaire du composant TTable.


Rappel sur les base de données :

C'est une façon de stocker l'information et d'établir des relations entre les différentes données. Par exemple on a tous pester par les publicités que l'on reçoit dans notre boîte aux lettres, nous précisant que l'on vient de gagner une machine à laver... Ce qui est surprenant, c'est que la société émettrice possède nos coordonnées précises, ainsi que celles de nos voisins, amis, famille etc etc..

Dans sa forme la plus basique, nous pouvons l'imaginer comme un tableau. Chaque colonne serait un renseignement comme "Nom, Prénom, adresse...." et chaque ligne correspondrait à une personne. D'un point de vue informatique, une base de données est constituée de un ou plusieurs fichiers constitués de une ou plusieurs tables (= nos tableaux vus plus haut). Car suivant la complexité des renseignements et leur caractères répétitifs, on peut facilement envisager de relier deux tables entre elles. On parle alors de base de données relationnelles. Bien sur il n'existe pas un seul format de base de données sur le marché.. Interbase, Oracle, Access, Paradox sont des noms très répandus dans les entreprises. On les choisis suivant le degré de complexité de la base, le nombre d'utilisateurs simultanés à utiliser la base .. et bien sur la grosseur de notre porte monnaie !

Pour notre exemple j'ai choisis Paradox pour sa simplicité : un fichier correspond à une seule et unique table, au contraire d'Access par exemple ou toutes les tables sont stockées dans le même fichier..... Une base de donnée Paradox est constitué d'un ou plusieurs fichier Paradox, normalement situé dans le même répertoire. Parfois suivant les ouvrages consacrés aux produits Borland, on parlera d'Alias de base de données. C'est une notion que j'ai choisi d'ignorer, car avant de jongler avec les différentes identités d'une base de données, il est préférable de voir comment elle fonctionne.

2. Première étape : la création du fichier Paradox

Pour cela nous utiliserons l'utilitaire fourni par Borland, appelé "Module Base de données" (pour ceux qui ont une version anglaise : Database Desktop).

On choisi le menu "Fichier->Nouveau->Table...". On doit avoir l'écran suivant :

Image non disponible

On choisit le format Paradox 7 et on valide.

Une nouvelle boite de dialogue apparaît :

Image non disponible

Elle sert à spécifier les champs de notre base de donnée.
Il faut la remplir de manière à obtenir ceci :

Image non disponible

Une fois encore, j'ai choisi que tous les champs serait du type alphanumérique dans un soucis de facilité.
Seul le premier champs est du type "numérique auto-incrémenté".
On enregistre la table sous le nom "Data.db" et on la place dans le même répertoire que notre futur projet.

3. Deuxième étape : La création du projet et sa mise en forme

Sous Delphi, on crée un nouveau projet et tout de suite on l'enregistre (un bon réflexe !). J'ai nommer le projet "Carnet" mais chacun fait ce qu'il veut ... L'unité principale est sauvegardée sous "UnitMain". Ma Form s'appelle "Main"

Voici son aspect général :

Image non disponible

Voici la déclaration des composants tel qu'on pourrait le voir dans le fichier "UnitMain.pas" :

 
Sélectionnez

Type
TMain = class(TForm)
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    GroupBox1 : TGroupBox;
    Menu : TMainMenu;
    Table: TTable;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    BoutonRecherche: TButton;
    BoutonModifier: TButton;
    BoutonNouveau: TButton;
    BoutonSupprimer: TButton;
    BoutonAnnulerSaisie: TButton;
    BoutonValider: TButton;
    FiltreNom: TEdit;
    RechercheNomEdit :TEdit;
    AdresseEdit: TEdit;
    PrenomEdit: TEdit;
    NomEdit: TEdit;
    VilleEdit: TEdit;
    TelMaskEdit: TMaskEdit;
    CPMaskEdit: TMaskEdit;
    Nouveau1: TMenuItem;
    Fichier1: TMenuItem;
    Modifier1: TMenuItem;
    Quitter1: TMenuItem;
    Aide1: TMenuItem;
    Apropos1: TMenuItem;
    BoutonSuivant: TButton;
    BoutonPrecedant: TButton;
    BoutonFirst: TButton;
    BoutonLast: TButton;
    ...

Je recommande vivement pour la compréhension du tutorial de nommer les composants de la même façon

La Form Main fait 650 en largeur (Width) et 230 en hauteur (Heigth).

Les propriétés importantes du TTable sont :

  • Active : Cette propriété détermine si effectivement l'application est reliée sur la table ou non.
  • DatabaseName : C'est le nom de la base de donnée ou de son Alias.
  • TableName : c'est le nom de la table. Chaque composant TTable ne peut être relié qu'à une seule et unique table. Dans notre cas (le format Paradox) la table correspond à un fichier.

Pour paramétrer notre TTable ("Table") :

  1. On détermine le nom de notre base de données dans la propriété DatabaseName. Par soucis de simplicité, nous allons laisser la base de données dans le même répertoire que notre application. Cette propriété restera donc vide, ce qui signifie au BDE qu'il doit chercher la base de donnée dans le répertoire de l'application.
  2. On choisit la table que l'on va contrôler par le composant. Si notre propriété DatabaseName est correctement remplie, le nom de notre fichier créé précédemment devrait apparaître dans la listbox. On le sélectionne.
  3. On met la propriété Active à true

Si tous est correctement configuré, il ne se passe... rien (par contre il y aura des messages d'erreur dans le cas contraire). Voici une vue de l'inspecteur d'objet sur le TTable :

Image non disponible

On en profite pour paramétrer le TDBGrid qui va nous servir à visualiser nos manipulations. Pour cela, il faut paramétrer d'abord le TDataSource ! Il sert de lien entre les composants visuels comme les TDBEdit, TDBMemo ... et les dérivés de TDataSet comme TTable, TQuery, TADOTable ...

Les propriétés importantes du TDataSource sont :

  • AutoEdit : sert à déterminer si tous les contrôles visuels peuvent ou non modifier la base de données. Dans notre cas la réponse est false, car la TDBGrid ne sert qu'à visualiser
  • DataSet : sert à determiner le composant qui est "relié" à la table, dans notre cas le TTable. Il doit logiquement apparaitre dans la listbox. Il faut le séléctionner bien sûr.

Enfin dans la TDBGrid, il faut lui signaler par sa propriété "DataSource" sur quelle composant DataSource elle doit se connecter. Prudence étant mère de Sûreté, j'ai mis la propriété ReadOnly de la DBGrid sur true. Sur l'exemple j'ai "enjolivé" la grille en modifiant ses propriétés dans ses propriétés Columns et Options. Là le bon goût étant subjectif, je laisse à chacun le soin de faire les modifications dont il jugera nécessaire...

Voilà la partie visuelle est terminée, on va pouvoir passer à la troisième étape.

4. Troisième étape : codage de la partie fonctionnelle

Voyons un peu les principes de fonctionnement de l'application. Son but est de gérer un petit agenda avec adresse et numéro de téléphone.
Nous devons donc prévoir :

  • un moyen de saisir les données (pour chaque nouvelle personne que nous rencontrons ...)
  • un moyen de supprimer les données (en cas de brouilles mortelles et irrémédiables...)
  • un ou plusieurs moyen(s) de retrouver les données (si on ne peut pas le consulter, un carnet ne sert à rien..)
  • un moyen de modifier les données (en cas de déménagement...)

Je rappelle que j'ai fait cette petite application dans un but didactique, mais aussi dans l'optique de m'en servir (et elle m'a servi longtemps...). J'avais donc rajouté quelques fioritures, comme par exemple rétracter la zone de saisie.

C'est pour cela que j'ai placé dans l'évènement OnCreate de la Form le code suivant :

 
Sélectionnez

procedure TMain.FormCreate(Sender: TObject);
begin
 Height:=235; // Retracte la fenêtre ..
 FiltreNom.Text:=''; // Vide le texte de FiltreNom
 RechercheNomEdit.Text :=''; // Vide le texte de RechercheNomEdit
end;

Notre application doit comporter des méthodes de modification, insertion, navigation dans les données.

Avant d'aller plus loin, il est intéressant de comprendre comment le TTable accède aux données.
Le TTable est un objet qui dérive de l'Objet TDataSet. Il implémente donc des procédure de navigation et d'ajout/suppression d'enregistrements.

Comme on l'a vu dans notre rappel sur les bases de données, on peut facilement visualisée une table comme un tableau ou les titres des colonnes serait le nom des champs. C'est ainsi que notre composant TDBGrid représente note fichier Paradox. Sur cette même TDBGrid, on remarque sur la gauche du composant un petit curseur. Il indique l'enregistre sur lequel pointe le TTable. Car le composant TTable ne pointe que sur un seul et unique enregistrement. Donc il nous faudra impérativement positionner le TTable sur l'enregistrement que l'on veut modifier. Il y a pour cela plusieurs façon de faire. La TDBGrid en implémente une : il suffit de sélectionner l'enregistrement pour que le TTable se positionne dessus. Toutefois si cette méthode est simple à mettre en oeuvre, elle est frustrante pour le développeur qui ne maîtrise pas le comportement du TTable.
Sur la Form, nous avons placé quatre boutons : Suivant, Précédant, Premier Enregistrement et Dernier Enregistrement, respectivement nommés : BoutonSuivant, BoutonPrecedant, BoutonFirs et BoutonLast.

Voici le code qu'il faut placer dans chaque évènement OnClick de ces boutons :

 
Sélectionnez

procedure TMain.BoutonSuivantClick(Sender: TObject);
begin
 Table.Next ; // Déplace le curseur sur l'enregistrement suivant
end;

procedure TMain.BoutonPrecedantClick(Sender: TObject);
begin
 Table.Prior ;// Déplace le curseur sur l'enregistrement précédant
end;

procedure TMain.BoutonFirstClick(Sender: TObject);
begin
 Table.First; // Déplace le curseur sur le premier enregistrement
end;

procedure TMain.BoutonLastClick(Sender: TObject);
begin
 Table.Last; // Déplace le curseur sur le dernier enregistrement
end;

A l'exécution (et sous réserve que votre table contienne des enregistrements !), on visualise très bien le résultat de ces méthodes grâce au curseur de la TDBGrid. Les méthodes Next et Prior servent à se déplacer d'enregistrement en enregistrement dans le sens croissant ou décroissant .. Les méthodes First et Last quand à elle servent à se positionner respectivement sur le premier et le dernier enregistrement.

Maintenant que nous savons nous déplacer dans les données, nous allons pouvoir y accéder, c'est à dire récupérer les valeurs pour les utiliser dans nos programmes. Pour cela regardons de plus près le code placé dans l'évènement OnClick de BoutonModifier. Dans notre petit programme, ce bouton sert à afficher les donner que nous voulons modifier.

 
Sélectionnez

procedure TMain.BoutonModifierClick(Sender: TObject);
begin
      // Boucle qui enclenche la procédure de modification d'une fiche client
 if((Table.RecordCount=0) and (Table.State <> dsInsert))
     // quitte la procédure si la table est vide et qu'on est pas en insertion
  then exit;
     // Activation du bouton Supprimer
 BoutonSupprimer.Enabled := true;
     // Désactive le bouton OK
 BoutonNouveau.Enabled:= false;
     // Désactive le menu fichier
 Fichier1.Enabled := false;
     // Aggrandi la fenêtre
 Height := 340;
     // Récupére le nom et le place dans le TEdit
 NomEdit.Text:=Table.FieldByName('Nom').AsString;
     // Récupére le prénom et le place dans le TEdit
 PrenomEdit.Text:=Table.FieldByName('Prenom').AsString;
     // Récupére l'adresse et le place dans le TEdit
 AdresseEdit.Text:=Table.FieldByName('Adresse').AsString;
      // Récupére la ville et le place dans le TEdit
 VilleEdit.Text:=Table.FieldByName('Ville').AsString;
      // Récupére le code postal et le place dans le TMaskEdit
 TelMaskEdit.Text := Table.FieldByName('Tel').AsString;
      // Récupére le téléphone et le place dans le TMaskEdit
 CPMaskEdit.Text := Table.FieldByName('CP').AsString;
end;

Cette partie du code sert uniquement à remplir les TEdit avec le contenu des champs. Pour cela on utilise la méthode FieldByName de la classe TTable. Elle renvoie un pointeur sur un objet TField. Comme l'objet TField sert à accéder à un champs d'une base de donnée... A partir de cet objet TField on récupère la propriété AsString que l'on copie dans la propriété Text du TEdit (ou TMaskEdit..).

Cela sous entend que l'on s'est positionné avant de vouloir lire les données.

Bien sur il y a aussi quelques petites fioritures aussi avec les activations de boutons et l'aggrandissement de la fenêtre pour afficher les zones de modifications.
On remarquera aussi le test qui vérifie qu'il y a quelque chose à modifier. La propriété RecordCount donne le nombre d'enregistrement dans la table. Si la table est vide il n'y a rien à modifier, sauf si on insère le premier enregistrement vide. C'est pour cela que l'on test aussi la propriété Table.State pour savoir si on est en mode insertion... Dans le cas contraire on quitte la boucle purement et simplement.

Une fois les données affichées et les modifications faites, il nous faut enregistrer notre travail. Pour cela nous allons ajouter sur l'événement OnClick de BoutonValider le code suivant :

 
Sélectionnez

procedure TMain.BoutonValiderClick(Sender: TObject);
begin
       // Positionne la table en mode Edition
 Table.Edit;
       //Place le nom dans le TEdit dans la table
 Table.FieldByName('Nom').Value := NomEdit.Text;
       //Place le prénom dans le TEdit dans la table
 Table.FieldByName('Prenom').Value := PrenomEdit.Text ;
       //Place l'adresse dans le TEdit dans la table
 Table.FieldByName('Adresse').Value := AdresseEdit.Text ;
       //Place la ville dans le TEdit dans la table
 Table.FieldByName('Ville').Value := VilleEdit.Text;
       //Place le téléphone dans le TEdit dans la table
 Table.FieldByName('Tel').Value := TelMaskEdit.Text;
       //Place le code postal dans le TEdit dans la table
 Table.FieldByName('Cp').Value := CPMaskEdit.Text;
       // Valide l'édition dans la base de données
 Table.Post;
       // Active le menu
 Fichier1.Enabled := true;
       //Active le bouton Supprimer
 BoutonSupprimer.Enabled := true;
       //Active le bouton Nouveau
 BoutonNouveau.Enabled := true;
       //Active le bouton Modifier
 BoutonModifier.Enabled := true;
       // Rétracte la fenêtre
 Height := 235;
end;

Ici nous accédons au champs par la propriété Value. Ce qu'il faut surtout remarquer, c'est que l'on place d'abord la table en mode "édition" avec la méthode Table.Edit. On signifie ainsi que les valeurs que nous plaçons dans les champs vont remplacer celles qui étaient stockées dans le fichier. Une fois que l'on a placé toutes nos valeurs, on signale au composant TTable qu'il doit valider les changements par la méthodes Table.Post;

Occupons nous de la partie "Création d'un nouvel enregistrement". Pour cela sur l'événement OnClick de BoutonNouveau on rajoute la procédure suivante :

 
Sélectionnez

procedure TMain.BoutonNouveauClick(Sender: TObject);
begin
     //Ajoute un enregistrement vide et se positionne dessus
 Table.Append;
     //Appelle la méthode de modification
 BoutonModifierClick(self);
end;

La méthode Append ajoute un enregistrement vide à la fin de la table et surtout positionne le curseur sur le nouvel enregistrement (c'est d'un compliqué...)
Une fois le nouvel enregistrement créer on appelle la méthode BoutonModifierClick qu'on a défini plus haut.

Enfin rajoutons maintenant la suppression d'enregistrements. On place dans l'évènement OnClick de BoutonSupprimer le code suivant :

 
Sélectionnez

procedure TMain.BoutonSupprimerClick(Sender: TObject);
var rep : integer;
begin
 rep:= MessageBox(Handle,'Etes-vous sûr de vouloir supprimer cette personne ?',
 'Avertissement',MB_OKCANCEL or MB_ICONSTOP ) ;
 if (rep =IDOK)
     //Si réponse OK Suppression de l'enregistrement
  then Table.Delete;
     //Activation du bouton nouveau
 BoutonNouveau.Enabled:= true;
    //Active l'item du menu Fichier
 Fichier1.Enabled := true;
    //Désactive le Bouton Supprime
 BoutonSupprimer.Enabled := false;
    //Taille de la fiche à 235 pixels
 Height := 235;
end;

La suppression de l'enregistrement se fait par la méthode Table.Delete. Bien évidemment il faut se positionner d'abord sur l'enregistrement à supprimer.
De plus, le BDE ne demandant aucune confirmation pour éviter les erreurs, c'est à nous de la coder ! Pour cela on utilise la fonction de l'API MessageBox(...) qui invoque une boîte de dialogue.

Il existe deux autres fonctionnalités intéressantes du composant TTable. Imaginons que nous avons un carnet d'adresse de Ministre. Pour retrouver le numéro de téléphone du coiffeur, si il faut appuyer quelques dizaines de fois sur le bouton "Suivant", on va se lasser très vite.

On va donc étudier la méthode Locate(...) à l'aide du code suivant que l'on saisi dans l'évènement OnClick de BoutonRecherche (celui ou c'est marqué Go ! )

 
Sélectionnez

procedure TMain.BoutonRechercheClick(Sender: TObject);
var Option : TLocateOptions;
begin
       //Test pour vérifier si le Edit est vide
 if RechercheNomEdit.Text <> '' then
  begin
      //Ajout de l'option "ne fait pas attention à la casse" des caractéres
  Option := [loPartialKey];
      //Recherche l'enregistrement suivant les critères
  Table.Locate('Nom',RechercheNomEdit.Text,Option);
  end;
end;

La méthode Locate permet de trouver un enregistrement à partir d'un champs. Ici nous recherchons un nom. Donc quand on va appelez la méthode Locate, le composant TTable va se positionner sur le prémier enregistrement dont le champ "Nom" à pour valeur le nom que l'on a saisi dans le TEdit . La partie la plus délicate est l'instanciation d'un objet TLocateOptions. Cet objet sert à déterminer les options de tris. Deux choix sont possibles : ignorer la casse, et regarder partiellement la valeur. Les deux choix peuvent être simultanés.

La deuxième fonctionnalité intéressante est le filtre. Nous allons implémenter dans notre petit programme un filtre sur les noms. Plaçons ce code dans les évenements OnChange et OnExit du TEdit FiltreNom.

 
Sélectionnez

procedure TMain.FiltreNomChange(Sender: TObject);
var Filtre : string;
begin
       // Constrcuction du Filtre avec le texte saisi dans la zone TEdit
 Filtre := 'Nom =''' + FiltreNom.Text + '*''';
       // Test si il n'y a rien dans le TEdit
 if FiltreNom.Text =''  then
  begin
       // Arrête le filtrage de la table
   Table.Filtered:=false;
       // Quitte la méthode
   exit;
  end;
      // Mise en place du filtre
 Table.Filter := Filtre;
     // Activation du filtre
 Table.Filtered := true;
end;

La construction du filtre se base sur le modèle suivant : Nom du champs, Opérateur de comparaison, Valeur de test.
Concrètement le champs est une chaîne de caractères AnsiString que l'on place dans la propriété Filter du composant TTable.
Une fois la propriété Filter renseignée, il faut activer le filtre en mettant la propriété Filtered à true.
On remarquera ici l'usage du caractère '*' dans le filtre qui est un caractère générique.

Et voilà il n'y a plus qu'à compiler le tout et observer.

Normalement on doit obtenir ceci :

Image non disponible

On va maintenant remplir notre carnet d'adresse, on clique sur le bouton Nouveau :

Image non disponible

Une fois que nous aurons entré plus d'enregistrements, nous pourrons tester une à une les méthodes que nous avons implémentées.

Bon courage

Sources

, consultant
(TeamB-fr)