mercredi 13 février 2002

MyBase


MYBASE

MyBase est une mini base de donnée fonctionnant avec le composant TClientDataSet. MyBase nécessite aucun moteur de base de donnée. MyBase utilise des fichiers xml ou binaire. Lors de son utilisation, il suffit d'inclure midas.dll sous windows ou midas.so sous linux.

Il est aussi possible de mettre MidasLib dans la clause du unit afin de ne pas être obligé de déployer les librairies mentionné ci-haut.MyBase fonctionne sous windows et linux, son utilisation peut donc s'avérer très intéressante.

Afin de faciliter la compréhension de MyBase, nous allons créer un programme fort simple de gestion de courriel pour des écoles. Nous verrons ainsi les relations maitre-détails. Chaque courriel sera associé à une école.

Préparation de la bd

A partir de l'onglet "accès bd, déposé sur la fiche 2 TDataSource et 2 TClientDataSet.


Inscriver à la propriété name d'un TClientDataSet cdsEcole pour l'autre inscriver cdsCourriel. Ensuite pour les TDataSource inscriver pour leur nom dsEcole et pour l'autre dsCourriel.


Ensuite relier le TDataSource au TClientDataSet grâce à sa propriété dataset. Pour dsEcole, choisisé cdsEcole faite de même pour dsCourriel.



Création d'une base de donnée

Maintenant nous allons créer les champs pour chaque clientdataset. cdsEcole aura un champ NoEcole et Ecole. cdsCourriel aura un champ courriel et noecole.
  • Sélectionner cdsCourriel, faite un click droit de la souris dessus. Cliquer sur "Editeur de champs..."

  • Faite une click droit de la souris dans la fenêtre blanche qui apparaît et cliquer sur Nouveau champ


  • Inscriver NoEcole dans la case Nom, la case Composant s'inscrit automatiquement. Pour ce champ, nous allons sélectionner le type AutoInc. Le système se chargera d'attribuer à chaque ajout une nouvelle valeur à ce champ. Pour le champ Ecole et courriel, sélectionner le type string et inscriver 25 dans la case taille.


  • Faite un click droit de la souris sur cdsEcole, cliquer sur "Créer un ensemble de donnée". Ensuite cliquer sur "Enregistrer dans une table Xml MyBase..." et tapé ecole comme nom de base de donnée. Faite de même pour cdsCourriel et nommer sa base de donnée courriel.

  • A la propriété de cdsEcole inscriver le nom de la base de donnée que vous avez créer précédemment: ecole.xml pour cdsEcole et courriel.xml pour cdsCourriel.


Nous allons maintenant permettre d'ajouter des écoles. Pour ce faire, déposer 1 TBouton et 1 TEdit sur la fiche.




Dans la propriété click du bouton pour ajouter une école, nous allons ajouter quelques instructions.

procedure TMyBase.cmdEcoleClick(Sender: TObject);
begin
  if txtEcole.text <> '' then 
  begin
    cdsEcole.Insert;
    cdsEcole.FieldByName('Ecole').AsString; := txtEcole.Text;
    cdsEcole.Post;
    txtEcole.Text := '';
  end;
end;
Insert, permet d'ajouter un enregistrement vide.

La deuxième instruction copie la valeur du TEdit dans le champ courant Ecole. La propriété FieldByName permet de trouver un champ par son nom. On peut ainsi leur affecter des valeurs.

Il est aussi possible d'y accéder par un index. Je vous conseille vivement d'aller regarder les nombreuses propriétés des TClientDataSet.

Post envoit les enregistrements dans un journal de modification. Les données ne seront écrites dans le fichier xml que lorsqu'on appellera la méthode mergechangelog.

Nous allons ajouter un TDBLookupComboBox à la fiche. Ce composant permettra de voir toutes les écoles disponibles.





La propriété "ListSource", permet d'établir la source de donnée qui remplira la TDBLookupListBox.

La propriété "ListField" correspond aux champs qui seront affichés dans la TDBLookupListBox. Il est possible d'en afficher plusieurs en les séparants par un ";". Il aurait donc été possible d'afficher le champ NoEcole et Ecole par l'instruction "NoEcole;Ecole".

La propriété "KeyField" sera utile lorsqu'on établira le lien pour effectuer la relation maitre/détail.Nous en parlerons en détail un peu plus loin.

Dans l'évènement AfterPost de cdsEcole, nous pouvons ajouter "cdsEcole.MergeChangeLog;". Ainsi les ajouts, modification, suppression qui auront été notés dans le journal de modification sont appliqué au fichier xml en appelant la méthode MergeChangeLog.

Après avoir ajouté quelques écoles, voici le résultat





Nous allons maintenant nous attaquer au courriel. Poser un dbgrid sur la fiche ainsi qu'un bouton. Modifiez la propriété datasource du dbgrid pour dsCourriel.
Dans la propriété click du bouton pour ajouter des adresses courriels, nous allons ajouter quelques instructions.

procedure TMyBase.cmdCourrielClick(Sender: TObject);
begin
  if cdsCourriel.state in [dsInsert, dsEdit] then cdsCourriel.Post;
end;

Puisque nous utilisons un composant lié directement avec une base de donnée, nous devons vérifier dans quel état est le clientdataset avant de faire un post. Si nous n'effectuons pas une vérification et que le clientdataset ne serait pas en mode insertion ou modification, il y aurait un message d'erreur qui s'afficherait. Cette vérification n'était pas nécessaire tantôt puisqu'on appelait la méthode insert, on attribuait une valeur au champ et finalement on appelait la méthode post. En liant le dbgrid au clientdataset beaucoup de travail est fait pour nous.

Dans l'évènement AfterPost de cdsCourriel, nous pouvons ajouter "cdsCourriel.MergeChangeLog;". Ainsi les ajouts, modification, suppression qui auront été noté dans le journal de modification sont appliqués au fichier xml en appelant la méthode MergeChangeLog.

Nous pouvons dès maintenant débuter à ajouter des courriels, mais ils ne seront pas lié à une école automatiquement.

Relation maitre/détail

Établir une telle relation est assez facile.
1) Sélectionner cdsCourriel, inscrivé dsEcole pour sa propriété MasterSource





2) Cliquer sur la propriété MasterFields. C'est ici qu'on va établir la relation maitre(ecole), détail (courriel)





Maintenant après avoir sélectionné une école, lorsque vous entrez un courriel le champ noecole sera lié. Ceci est dû à la propriété KeyField du TDBLookupListBox.

À partir de ce moment, lorsque vous sélectionnerez une école, seul les courriels qui y sont lié seront affichés.

Vous pouvez visionner le contenu des fichier xml en tout temps à l'aide d'un navigateur web.
Vous pouvez télécharger les sources du projet ici.

dimanche 3 février 2002

Exception

EXCEPTION
Tout programme n’est pas à l’abri d’erreurs : valeur erronée, fichier introuvable, type de donnée incompatible... Se mettre dans la peau d’un usager aide à voir le type d’erreur qu’il pourrait faire. On doit gérer les erreurs d'un programme avec les exceptions, même s'il est possible de le faire autrement.
Répondre aux exceptions
Lorsqu'une exception survient, l'application lève une exception. On peut ainsi exécuter une partie de code fonctionnel et détruirel'erreur.
Certaine ressources devraient toujours être protégées
  • Les fichiers
  • La mémoire
  • Les ressources de Windows ou de Linux
  • Les objets
La syntaxe des traitements des exceptions est simple

try avec except


try
  instruction
except
  on TypeException do begin
  instruction
end;
end;

Le mot try débute le bloc d’exception, on inscrit les instructions voulues. Si durant le 
déroulement du programme une exception de type TypeException est levé, les instructions de ce 
bloc seront exécutées 

try avec finally

Quoiqu'il arrive dans le déroulement du programme, le code contenu dans le bloc finally sera exécuté s'il y a une erreur ou non
try
   instruction
finally
   instruction
end;

var
  bit:tbitmap;
begin
  try
    bit  := tbitmap.Create;
  finally
    bit.free;
  end;
end;

Librairie d'exécution

Lorsqu'on utilise les librairies d'exécution (rtl)comme les fonctions, les procédures de fichiers, les conversions..., les rtl reportent les erreurs à l'application sous la forme d'exception. Un message généré à l'usager lui sera affiché. On peut définir nos propres exceptions lorsqu'on fait appel à ce type de librairie.

begin
  try
    Result:=Dividende div Diviseur;
  except
    on EDivByZero do
    begin
      result:=0;
      showMessage('Division par zéro impossible');
    end;
  end;
end;
On pourrait arriver aux mêmes résultats en utilisant un if, mais l'utilisation des exceptions est beaucoup plus efficace.
Code source disponible ici.

Définir ses exceptions

Afin de sécuriser nos applications contre d'éventuelles erreurs, on peut créer nos propres exceptions afin de les prévenir. Les exceptions sont des objets, alors nous devons les déclarer comme un objet.

type
   EMotInvalide = class(Exception);
Après avoir déclaré notre exception, on peut l'appeler à tout moment. On doit employer le mot raise pour appeler l'exception.
if Mot == MotInvalide then 
   raise EMotInvalide.create('Mot invalide');

Les exceptions silencieuses

Les applications de Delphi manipulent la plupart des exceptions que votre code ne manipule pas spécifiquement en affichant un message d'erreur. Il est possible d'arriver au même résultat en utilisant les exceptions dites silencieuses, qui n'afficheront pas de message d'erreur à l'usager. Ce type d'exception est particulièrement intéressante, lorsqu'un veut arrêter une partie d'un programme.

Pour ce faire, on utilise la procédure Abort;

samedi 26 janvier 2002

Enregistrement

ENREGISTREMENT
Les enregistrements sont un regroupement de données qui ont un lien entre elles. Un enregistrement équivaut à une structure en langage c. On regroupe donc plusieurs variables sous une seule. Une telle approche évite à devoir créé plusieurs variables. On travaille avec une variable au lieu de plusieurs, le risque d'erreur est diminué.

TInfoClient = record
Prenom:string[20];  
Nom:string[20];   
Adresse:string[30];   
Ville:string[20];   
CodePostal:string[6];
end;

Champs

Les éléments de l'enregistrement: Prenom, Nom... sont appelés des champs. Après avoir défini le type, on peut créer des instances, variables de ce type. On accède au champ de l'enregistrement en apposant un point devant le nom de l'enregistrement.
var
InfoClient:TInfoClient;
begin
  InfoClient.Prenom:='Paul';  
  InfoClient.Nom:='Smith';  
  InfoClient.Adresse:='3455 Cartier'; 
  InfoClient.Ville:='Montreal';  
  InfoClient.CodePostal:='J4S1R4';
end;

With

Lorsqu'on a plusieurs variables à écrire ça devient vite fastidieux. On peut alléger le code en utilisant «with».
var
InfoClient:TInfoClient;
begin
  with InfoClient do 
  begin      
    Prenom:='Paul';
    Nom:='Smith';
    Adresse:='3455 Cartier';
    Ville:='Montreal';
    CodePostal:='J4S1R4';
  end;
end;

Tableau d'enregistrement

Les tableaux peuvent aussi être incorporés dans les enregistrements. C'est lorsqu'on définit l'instance qu'on a créé le tableau.
var
   Etudiant:array [1..5] of TEtudiant;
begin
   Etudiant[1].Prenom:='Roger';
   Etudiant[1].Nom:='Demers';
   Etudiant[1].Matiere:='Informatique';
   Etudiant[2].Prenom:='Jean';
   Etudiant[2].Nom:='Ducharme';
   Etudiant[2].Matiere:='Chimie';
end;
Code source disponible ici.

vendredi 25 janvier 2002

Tableau


TABLEAU

Un tableau est un ensemble de valeur. On peut mettre n'importe type standard dans un tableau. Ils permettent de relier des données ensemble au lieu de créer plusieurs variables. Disons que vous devez créer un programme qui calculer la moyenne des notes des étudiants d'une classe. Vous pourriez créer autant de variables qu'il y a d'étudiant, mais ça serait difficile et fastidieux à gérer.

Une solution consisterait à utiliser un tableau

var tabNote:array [0..24]of real;

Ce qui fera    150 octets (25 éléments * 6 octets pour un real) On peut représenter    en mémoire un tableau comme voici. 

tabNote[0]
tabNote[1]
tabNote[2]
La mémoire est utilisée de façon linéaire, chaque fois qu'on avance d'un élément, on avance de 6 octets dans la mémoire. On doit spécifier l'index d'un tableau lorsqu'on l'initialise. L'index c'est le chiffre qu'on spécifie entre les crochets «[]».

tabNote[0]:=23;
tabNote[21]:=144;

Les opérations

Les opérations entre tableaux sont aussi possibles
notePaul:=tabNote[3] + tabNote[12] - tabNote[5];

Les tableaux multidimensionnels

Les tableaux multidimensionnels peuvent aussi être créés. On ne doit qu'ajouter un deuxième indice à la syntaxe déjà apprise. var tabNote:array [0..2 ,0..1] of integer; Les deux syntaxes sont équivalentes. Les opérations entre tableaux peuvent aussi être faites. La représentation en mémoire est la même, de la gauche vers la droite et on change de ligne

tabNote[0][0]
tabNote[0][1]
tabNote[0][2]
tabNote[1][0]
tabNote[1][1]
tabNote[1][2]

Les tableaux sont souvent la cause de beaucoup d'erreurs chez les  programmeurs.
Il est très aisé de faire une erreur de débordement.

var
  tabNote:array [0..2] of integer;
begin
  tabNote[8]:=45;
end;

Ce code engendra une erreur à la compilation. Afin d'empêcher
que de telle erreur se produise, on peut utiliser les fonctions  low et high.
Ces fonctions renvoient les limites inférieures et supérieures
d'un tableau.

var
  bas,haut:integer
  tabNote:array [10..34] of integer;
begin
  bas:=low(tabNote);//ce qui équivaut à 10
  haut:=high(tabNote);//ce qui équivaut à 34
end;

On peut comparativement à d'autres langages créer un tableau
ne débutant pas à zéro. Cette possibilité peut
s'avérer intéressante afin de résoudre certains problèmes.

var
tabNote[10..22] of integer;

Les tableaux dynamiques

Jusqu'à maintenant, on n'a créé que des tableaux statiques. Ce type de tableau a le désavantage de ne pouvoir se modifier durant l'exécution du programme. Une fois le tableau défini, on ne peut l'agrandir, le rétrécir.

Si vous avez déjà programmé des tableaux dynamiques en langage c, c++ vous savez comment il peut être compliqué de le faire pour un novice. Vous serez sûrement heureux d'apprendre que, depuis la version 4 de delphi, il est aisé de manipuler de tel tableau. On n'a qu'à ne pas spécifier de taille lorsqu'on déclare le tableau

var
  tabNote:array of integer;
  Grandeur:integer;
begin
  Grandeur:=SpecifierGrandeur;
  SetLength(tabNote,Grandeur);
end;
Maintenant, on a un tableau de la grandeur que l'on veut. L'indice inférieur d'un tableau dynamique débute toujours à l'indice zéro.

var
  tabNote:array of integer;
  Grandeur:integer;
begin
  Grandeur:=100;
  SetLength(tabNote,Grandeur);
  //Traitement on retrecit le tableau
  SetLength(tabNote,5);
  //on agrandit le tableau
  SetLength(tabNote,10);
end;

Les tableaux multidimensionnels peuvent aussi être crées dynamiquement
var
  lpPoint:TPoint;
begin
  Grandeur:=0;
  while (ok=false) do
  begin
    GetCursorPos(lpPoint);
    Grandeur:=Grandeur+1;
    //augmente la première dimension du tableau
    setlength(tabPoint,Grandeur,2);
    tabPoint[Grandeur-1,0]:=lpPoint.x;
    tabPoint[Grandeur-1,1]:=lpPoint.y;
  end;
end;

L'utilité des tableaux est innombrable, mais gare au débordement. :)

mardi 22 janvier 2002

Commentaire


COMMENTAIRE

Les commentaires sont utilisés dans les programmes afin de rendre le programme plus aisément compréhensible. Il y a trois façons d'inclure un commentaire dans un programme
  • {Programme conçut Marc Collin}
  • (* Fonction permettant de permuter 2 tableaux*)
  • //Écrit en delphi 5
Lorsqu?on écrit un commentaire sur plusieurs lignes, il est plus simple d'utiliser les accolades que d'avoir à retaper pour chacun ligne le slash.

{Creer par: Marc Collin Date: 
 2 octobre 2000 
But: Programme calculant l'accélération} 

vendredi 18 janvier 2002

Opérateur


OPÉRATEUR

Opérateur d'affection


Opérateur Description Exemple
:= Affection x := 10;

Opérateur mathématique


Opérateur Description Exemple
+ Addition x := y + 56
- Soustraction x := y - 3
* Multiplication x := y * 6
/ Division réel x := y / 5.6
div Division entière x := y div 5

Opérateur d'égalité


Opérateur Description Exemple
= Égale if ( x = 5) then...
<> Différent de if ( x <>15) then...
< Inférieur à if ( x < 67) then...
> Supérieur if ( x > 99) then...
<= Inférieur ou égale à if ( x <= 12) then...
>= Supérieur ou égale à if ( x >= 24) then...

Opérateur logique


Opérateur Description Exemple
and Et logique if (x=4) and (y=5) then..
or Ou logique if (x=45) or (y=23) then..

Opérateur unaire


Opérateur Description Exemple
^ Pointeur pNom:= ^Nom;
@ Adresse ptrtab := @tabNom;
and Et bit-à-bit x := x and $03;
or Ou bit-à-bit x:= x or $AA;
not Non bit-à-bit x:= x and not $AA
not Non logique if not Valide then...

Opérateur diver


Opérateur Description Exemple
$ Valeur hexadécimale x := $ff;
[] Indice de tableau x := tabNom[4];
. Qualification x:=y.create;

mercredi 16 janvier 2002

Types scalaires


TYPES SCALAIRES

Delphi possède de nombreux types de donnée. Le type de donnée détermine la valeur qui peut être attribuée aux variables.

Les types entiers

Type Intervalle Format/taille
Byte 0..255 non signé, 1 octet
Shortint -128..127 signé, 1 octet
Char 0..255 non signé, 1 octet
Widechar 0..65 535 non signé, 2 octets
Smallint -32 768..32 767 signé, 2 octets
Word 0..65 535 non signé, octets
Longint -2147483648.. 2147483647 signé, 4 octets
Integer -2147483648.. 2147483647 signé, 4 octets
Cardinal 0..4 294 967 295 non signé, 4 octecs
Int64 -9 223 372 036 854 775 808..9 223 372 036 854 775 807 signé, 8 octect

Les types réels

Type Intervalle Taille en octets
Real 2.9 10-39..1.7 1038 6
Double 5.0 10-324..1.7 10308 8
Real 2.9 10-39..1.7 1038 6
Extended 1.9 10-4951..1.1 104932 10
Comp -263+1..263-1 8
Currency -922337203685477.5808..
922337203685477.5807
8

Autres types

Type Valeur Taille en octets
Boolean True ou false 1
Variant varialbe 16

Le type de variant est à déconseiller lorsqu'on désire de la performance, car il s'adapte au type de donnée. Il utilisera toujours 16 octets même si sa valeur est égale à 1. Il est extrêmement lent.