Cours Delphi

Cours de Ière Applications Delphi pdf


Télécharger Cours de Ière Applications Delphi pdf

★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Télécharger aussi :


Deuxième partie :

Cours de Ière

Applications Delphi

                                                                 page 49 de 87                                                                  

7 Delphi

7.1 Introduction

Après son lancement, Delphi se présente sous la forme de 4 fenêtres.

La première fenêtre occupe la partie supérieure de l'écran. Elle correspond à l'environnement de programmation proprement dit.

Cette fenêtre contient :

•   la barre de titre ;

•   la barre de menu de Delphi ;

•   une zone « barre d'outils » (sur la gauche) ;

•   une zone contenant les divers composants regroupés par familles.

La seconde fenêtre se trouve par défaut à gauche de l'écran : c'est l'inspecteur d'objets. Il permet de visualiser, pour chaque objet ou composant, les propriétés et les événements auxquels l'objet peut répondre.

La troisième fenêtre constitue la fiche principale de la future application Delphi. Il s'agit, au départ, d'une fenêtre vide dans laquelle on placera les divers objets.

La dernière fenêtre, cachée sous la précédente constitue l’éditeur proprement dit, contenant le code source de l'application.

Pour démarrer une nouvelle application, il faut choisir l'option New Application du menu File.

Pour sauvegarder une application, il faut choisir l'option Save All du menu File. Une règle à suivre absolument est de créer un répertoire par application. Comme Delphi crée plusieurs fichiers pour une application donnée, il est plus facile de les retrouver s'ils ne sont pas enregistrés avec d'autres fichiers de noms pratiquement identiques.

Lors du premier « tout enregistrement » de l'application, une fenêtre permet de choisir l'emplacement de sauvegarde et même de le créer.

Pour exécuter une application, il faut choisir l'option Run du menu Run. Si les options d'autoenregistrement ont été sélectionnées et que l'application n'a encore jamais été sauvegardée, la fenêtre d'enregistrement s'affiche. L'application est ensuite compilée puis exécutée, si elle ne contient pas d'erreur.

7.2 Les fichiers utilisés en Delphi

Les fichiers d'un projet :

.DPR 

fichier projet                                                   

Delphi Project File

.DFM 

fichier fiche                                                     

Delphi Form File

.PAS 

fichier unité - code source

 

.EXE 

fichier exécutable (le programme développé)

 

.DCU 

fichier unité - code compilé                             

Delphi Compiled Unit

.RES 

fichier ressource (icônes, bitmaps, curseurs, . . .)

 

.DPL 

fichier paquet compilé                                     

Delphi Package Library

.DPK 

fichier paquet source                                        

Delphi Package


Les fichiers .DPR, .DFM et .PAS sont les fichiers nécessaires à la programmation et doivent être copiés pour continuer le développement sur une autre machine.

Autres fichiers :

.DOF               options du projet                                                         Delphi Options File

.DSK                paramètres du bureau                                                 Delphi Desktop File

.~??                  fichiers de sauvegarde

7.3 L’approche Orientée-Objet

Dans la programmation en Delphi, nous allons manipuler des objets. Ces objets sont définis par leurs propriétés, leurs méthodes et leurs événements.

Dans la vie courante, un objet peut être toute chose vivante ou non (par exemple : une voiture, une montre, …). En informatique, un objet est souvent un bouton, une fenêtre, un menu, …

7.3.1      Les propriétés

Cependant, chaque personne « voit » l’objet différemment. Par exemple chacun aura une perception différente de l’objet voiture, selon l’importance qu’il attribue aux caractéristiques de l’objet.

Une propriété est une information décrivant une caractéristique de l’objet.

Ainsi, il est facile d’énumérer quelques propriétés pour l’objet voiture : vitesse maximale, cylindrée, marque, modèle, couleur, …

Nous pouvons consulter les propriétés et également les modifier. 

Par exemple, nous pouvons définir les propriétés d’une voiture dans un jeu de course, tel que la couleur. Ceci se fait de la manière suivante :

Voiture1.Couleur := Rouge

Bien entendu, il faut que la constante « Rouge » soit définie.

Les objets (dans Delphi ces objets sont appelés composants) que nous allons utiliser sont prédéfinis (boutons, fenêtres, menus, …). Pour afficher les propriétés d’un objet, il suffit de cliquer dessus. Les propriétés s’affichent alors dans l’inspecteur d’objet.

Il existe des composants en lecture seule.

7.3.2      Les méthodes

Pour simplifier, on peut se représenter une méthode comme un ordre du style « fais ceci ». Cet ordre provoque l’exécution d’une certaine action par l’objet.

Par exemple, pour l’objet voiture, on peut énumérer les méthodes suivantes : accélérer, freiner, changer de vitesse, … Donc, l’instruction élérer(10)  indique à la voiture qu’elle doit accélérer d’un facteur 10.

Les propriétés ne font que changer une caractéristique d’un objet alors que les méthodes effectuent une action. On n’utilise pas de signe d’affectation lorsqu’on exécute une méthode.

7.3.3      Les événements

Pour chaque objet, il peut survenir certains événements, qui déclenchent des réactions.

Dans l’exemple de la voiture, lorsqu’on tourne la clé dans le contact ou lorsqu’on appuie sur l’accélérateur, la voiture respectivement démarre ou accélère.

Pour les objets informatiques il leur arrive des événements auxquels ils peuvent réagir. 

Par exemple, un bouton peut avoir les événements OnMouse… (événements liés à la souris), OnKey… (événements liés au clavier), OnEnter (réception du focus), On Exit (perte du focus), … Les événements existants pour un objet sont visibles dans l’inspecteur d’objet.

7.4 Passage Pascal – Delphi – un premier exemple

7.4.1      L'interface

En Delphi, nous utiliserons les composants de l'interface graphique (les fenêtres de Windows) pour entrer les données et afficher les résultats. Les algorithmes PASCAL que nous avons utilisés jusqu’à maintenant pour obtenir les résultats pourront rester inchangés.

D'abord, nous allons créer l'interface du programme. Nous allons adapter les noms internes (propriété Name) de chaque composant que nous utilisons. 

Bouton (TButton)

Name: btnCalcul

Caption: Moyenne

Boîte d'édition

(TEdit)

Name: edtB

 Boîte d'édition

(TEdit)

 Name: edtA

En plus, nous allons modifier les inscriptions sur les différents composants (propriétés Caption ou Text).

7.4.2      Les conversions de types

Les données inscrites dans les boîtes d’édition sont de type texte (string). Nous devons donc les transformer afin de pouvoir effectuer des calculs.

Voici quelques fonctions permettant d’effectuer certaines conversions :

StrToInt(string) : convertit une chaîne de caractères en un nombre entier (type integer) StrToFloat(string) : convertit une chaîne de caractères en un nombre réel (type real).

De même, pour pouvoir afficher le résultat, nous devons le transformer en texte. Ceci peut se faire grâce aux fonctions FloatToStr et IntToStr.

7.4.3      Le traitement

Après la saisie des données dans les boîtes d'édition, l'utilisateur va cliquer sur le bouton btnCalcul. À cet instant l'événement OnClick du bouton est généré et la méthode btnCalculClick est lancée. Nous allons donc entrer les instructions à effectuer dans la méthode btnCalculClick :

procedure TfrmMain.btnCalculClick(Sender: TObject); var A,B,MOY : real; begin

A  := StrToFloat();

B  := StrToFloat();   MOY := (A+B)/2; lblMoy.Caption := FloatToStr(MOY); end;

7.4.4      Exercices

Exercice 7-1

Ecrivez un programme qui affiche le plus grand de trois nombres réels A, B, C.

Exercice 7-2

Ecrivez un programme qui calcule la somme d'une série de nombres entrés au clavier, en utilisant deux boîtes d’édition et un bouton pour la remise à zéro de la somme.

Exercice 7-3

Réalisez le programme PUISSANCE qui calcule et affiche la puissance XN (puissance X exposant N pour un réel X et un entier N positif, négatif ou zéro).

Pour les cas où XN ne se laisse pas calculer, affichez un message d'erreur !

Exercice 7-4

a)   Réalisez un programme qui permet de simplifier une fraction.

b)   Utilisez une partie du programme réalisé sous a) pour faire un programme qui additionne deux fractions.

7.5 Calcul de la factorielle

Comme premier programme essayons d’implémenter en Delphi le calcul de la factorielle. 

                                                                                                   ?1?K? x    si x ?1

Rappelons que  pour tout entier naturel x, x!= ? ? 1 si x = 0

Pour élaborer ce calcul nous pouvons utiliser le programme développé dans le cours de 2e et l’incorporer dans celui en  Delphi.

7.5.1      Présentation visuelle

Commençons par établir un formulaire dans lequel nous notons les valeurs et éditons les résultats.

Voici un exemple d’un tel formulaire.

 

                                                                                         btnOk                    btnExit

Ce formulaire est un nouvel objet que nous appellerons Tformulaire, de capture (Caption) : Factorielle (algorithme itératif). Il est composé des propriétés suivantes :

Name

type

text

Caption

lblTitre 

TLabel

Calcul de la factorielle d’un nombre

lblEgal

TLabel

! =

edtNombre 

TEdit

valeur de la factorielle à calculer

lblResultat

TLabel

btnOk

TButton

Calcul

btnExit

TButton

Sortir

Il est évident que tous ces champs possèdent encore davantage de propriétés. Nous n’avons énuméré ici que les plus importantes.

7.5.2      Code

Une fois ce formulaire établi, nous pouvons écrire le code nécessaire pour calculer la factorielle. Rappelons que nous y utiliserons le code Pascal établi en 2e (voir également les « Algorithmes obligatoires »).

Delphi s’occupera de la déclaration du formulaire et de ses propriétés.

La seule partie du code que nous devons écrire est celle de la procédure btnOkClickqui va être exécutée, comme son nom le dit, après que l’utilisateur ait poussé sur le bouton Ok. Nous dirons que la procédure s’exécute après l’événement onClick appliqué à la propriété btnOk.

Le tout se trouvera dans l’unité Unit1.

Voici une possibilité de code pour la procédure en question.

procedure Tformulaire.btnOkClick(Sender: TObject); var n,fact:integer; begin   n:=StrToInt(); fact:=factorielle(n);   lblresult.Caption:=IntToStr(fact) end;

Bien entendu, cette procédure suppose que la fonction factorielle(n:integer):integer est définie.

7.5.3      Explication du programme.

En regardant de près ce code quelques remarques s’imposent :

? Comme la procédure s’emploie dans le formulaire Tformulaire, elle s’appellera sous son nom complet : Tformulaire.btnOkClick.

? La valeur saisie du nombre est la valeur de la propriété Textdu champ edtNombre. Nous notons donc cette valeur par . De plus, comme il s’agit d’une chaîne de caractères, nous devons encore transformer cette chaîne en une valeur numérique par la fonction StrToInt, fonction prédéfinie dans Delphi.



? La valeur de la factorielle calculée sera affectée à la propriété Caption du champ lblResultat que nous noterons par lblResultat.Caption. Comme de plus cette valeur doit être du type chaîne de caractères, nous devons transformer fact par la fonction IntToStr, autre fonction prédéfinie dans Delphi.

L’unité Unit1 se présentera finalement ainsi : 

unit Unit1; interface uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,  Forms, Dialogs, StdCtrls;

 type

  Tformulaire = class(TForm) lblTitre: TLabel;     edtNombre: TEdit;     lblEgal: TLabel;     btnOk: TButton;     lblResultat: TLabel;     procedure btnOkClick(Sender: TObject);     procedure FormCreate(Sender: TObject);   private

    { Private declarations }   public

    { Public declarations }   end; var

  formul: Tformulaire; implementation

{$R *.dfm}

//fonction permettant de calculer une factorielle function factorielle(n:integer):integer; var fact:integer; begin   fact:=1;   while n>1 do   begin     fact:=fact*n; n:=n-1   end;   result:=fact end;  procedure TFormulaire.btnOKClick(Sender: TObject); var n,fact:integer; begin   n:=StrToInt(); fact:=factorielle(n);   lblresult.Caption:=IntToStr(fact) end;  procedure TFormulaire.btnexitClick(Sender: TObject); begin

  Application.Terminate; end;  end.

7.5.4      Exécution du programme

Une fois ce code saisi, nous sauvegardons le tout dans un répertoire réservé à cette application. Nous cliquons ensuite sur le bouton qui représente un petit triangle vert et le programme s’exécutera.

7.5.5      Remarques

? La méthode Tformulaire.btnExitClick aura comme seule commande Application.Terminate. De cette manière l’événement Click lié au bouton btnExit aura comme effet net d’arrêter l’application.

? La saisie fautive respectivement d’un nombre négatif ou décimal ne conduira pas à un message d’erreur de la part du programme mais nous affichera un résultat erroné. Nous laissons au lecteur le soin de corriger le programme pour l’améliorer de ce point de vue.

7.6 Equation du second degré

Écrivons maintenant un programme qui demande à la saisie les trois coefficients a, b et c d’une équation du second degré et qui calcule, si elles existent, les racines de l’équation ax2 + bx + c = 0 . 

Ce même programme a été demandé comme exercice dans le cours de 2e. Nous en faisons ici un programme Delphi. 

7.6.1      Présentation visuelle

Comme dans l’exemple précédent nous commençons par dessiner un formulaire que nous appellerons Tformulaire, dont l’instance formulairenous permet de saisir les coefficients et de lire le(s) résultat(s). La propriété Captionde l’objet Tformulaire aura comme valeur : équation du 2e degré

Ce formulaire est composé des champs suivants :

name

type

text

caption

lblA 

TLabel

a =

lblB

TLabel

b =

lblC

TLabel

c =

lblTexte

TLabel

texte sur le résultat

lblX1

TLabel

valeur de la racine

lblX2

TLabel

valeur de la racine

edtA

TEdit

valeur de a

edtB

TEdit

valeur de b

edtC

TEdit

valeur de c

btnCalcul

TButton

Calcul

gbCoeff

TGroupBox

Coefficients

gbRes

TGroupBox

Résultat

btnExit

TButton

Sortir

Nous remarquons tout-de-suite une nouvelle notion :

? les champs du type TGroupBox : Ils servent à regrouper différents champs dans un même groupe qu’ils affichent avec un cadre et un nom donné sous Caption. Dans notre exemple la TGroupBox gbCoeff regroupe les champs lblA, lblB et lblC, tandis la TGroupBoxgbRes affichera les résultats et contient ainsi les champs lblTexte, lblX1 et lblX2. Nous définissons ces TGroupBox comme suit :  

? Nous venons déjà de remarquer que le résultat sera affiché dans la TGroupBox gbRes.

Mais les étiquettes (labels) lblTexte, lblX1 et lblX2 sont invisibles pour l’instant. Si nous avons un résultat à afficher, lblTexte contiendra une des phrases suivantes : Il n'y a pas de solution réelle ! ,

Il existe une solution réelle ! ou 

Il y a deux solutions réelles différentes ! (ceci en fonction du résultat du calcul), tandis que lblX1 et lblX2 contiendront les valeurs des racines éventuelles. Comme actuellement ces étiquettes ne contiennent pas de texte (caption vide), elles n’apparaîtront pas à l’écran.

7.6.2      Code

Une fois ce formulaire établi nous écrivons le code suivant :

unit Unit1; interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons; type

  Tformulaire = class(TForm) gbCoeff: TGroupBox;     lblA: TLabel;     lblB: TLabel;     lblC: TLabel; edtA: TEdit;     edtB: TEdit;     edtC: TEdit;     btnCalcul: TButton; gbRes: TGroupBox;     lblTexte: TLabel;     lblX1: TLabel;     lblX2: TLabel;     btnExit: TButton;     procedure btnCalculClick(Sender: TObject);     procedure btnExitClick(Sender: TObject);   private

    { Private-Declarations}   public

    { Public-Declarations }   end; //Tformulaire var formulaire: Tformulaire; implementation {$R *.DFM} procedure Tformulaire.btnCalculClick(Sender: TObject); var a,b,c,disc : real; begin   a:=StrtoFloat(); b:=StrtoFloat();   c:=StrtoFloat();   disc:=b*b-4*a*c;   if disc < 0 then   begin

    lblTexte.Caption:='Il n''y a pas de solution réelle !'; lblX1.Caption:='';     lblX2.Caption:='';   end   else if round(disc*1000000) = 0 then //un nombre reel n’est jamais 0   begin     lblTexte.Caption:='Il existe une solution réelle !'; lblX1.Caption:='x = ' + FloattoStr(-b/(2*a));     lblX2.Caption:='';   end else if disc > 0 then   begin     lblTexte.Caption:='Il y a deux solutions réelles différentes !'; lblX1.Caption:='x1 = ' + FloattoStr((-b-sqrt(disc))/(2*a));     lblX2.Caption:='x2 = ' + FloattoStr((-b+sqrt(disc))/(2*a));   end; end;  procedure Tformulaire.btnExitClick(Sender: TObject); begin

  Application.Terminate; end;  end.

7.6.3      Explications du programme

Nous lisons d’abord les 3 coefficients a, b et c de l’équation. Comme nous les avons définis comme variables réelles, nous devons utiliser la fonction StrtoFloatpour faire la transformation entre la chaîne de caractères que représente edt*.Ttextet les variables a, b et c.

Nous calculons ensuite le discriminant. En fonction du signe du discriminant nous envisageons les 3 cas : 

? disc<0 : il n’y a pas de résultat réel ; 

? disc=0 : il y a une racine ;

? disc>0 : il y a deux racines réelles distinctes.

En fonction des différents cas nous calculons les valeurs des racines.

À la fin il nous reste encore à transformer les valeurs réelles, résultats des calculs, en chaînes de caractères pour les affecter à la propriété Caption des différentes étiquettes. Nous faisons ceci avec la fonction FloatToStr.

La méthode Tformulaire.btnExitClick aura comme seule commande Application. Terminate. De cette manière l’événement Click lié au bouton btnExit aura comme effet-net d’arrêter l’application.

7.7 Vérification du numéro de matricule

Développons ici un exercice qui prend  en entrée le numéro de matricule d’une personne et qui vérifie que le chiffre de contrôle est correct.

7.7.1      Rappelons la méthode de calcul du numéro de contrôle.

Si nous notons a1a2a3a4m1m2 j1 j2n1n2c un numéro de matricule, nous formons le dernier chiffre en parcourant  les étapes suivantes :

?

Nous formons la somme : 

sum = 5*a1 + 4*a2 +3*a3 + 2*a4 + 7*m1 + 6*m2 +5* j1 + 4* j2 +3*n1 + 2*n2 ;

?

soit n le reste de la division de sum par 11 ;

?

si n=1 il y a une faute ; 

?

si n=0 le chiffre de contrôle reste 0 ;

?

si n ? 0 et n ?1 alors le chiffre de contrôle vaut 11? n .

Nous essayons de traduire ceci en Delphi. 

7.7.2      Présentation visuelle

Pour cela il nous faut d’abord un formulaire que nous appellerons, comme toujours,  Tformulairedont une instance nous servira à manipuler les entrées et sorties.

La valeur de la propriété Caption de l’objet Tformulaire sera :  Numéro de matricule.

Voici un exemple d’un tel formulaire.

Il contient les éléments suivants :

nom

type

text

caption

lblTitre 

TLabel

Contrôle du numéro de

matricule

lblSaisie 

TLabel

Indiquez votre numéro de matricule :

lblResultat

TLabel

Votre numéro de matricule est :

edtSaisie   

TEdit

numéro de matricule

edtResultat

TEdit

correct/faux

btnVerif

TButton

Vérification

btnExit

TButton

Sortie

7.7.3      Code

Une fois ce formulaire établi, nous devons programmer le code nécessaire.

Voici un exemple d’implémentation.

unit Unit1; interface uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type

  TfrmMatricule = class(TForm) lblTitre: TLabel;     lblSaisie: TLabel;      lblResultat: TLabel; edtSaisie: TEdit;     edtResultat: TEdit;     btnVerif: TButton; lblResultat: TLabel;     btnExit: TButton;

         procedure btnVerifClick(Sender: TObject);     procedure btnExitClick(Sender: TObject);   private

    { Private declarations }   public

    { Public declarations }   end; //Tformulaire var   frmMatricule: TfrmMatricule;

   implementation {$R *.dfm}

procedure TfrmMatricule.btnVerifClick(Sender: TObject); var   a1,a2,a3,a4,m1,m2,j1,j2,n1,n2,nc,c: integer;   sum : integer;   s : string; begin   ;   if length(s) <> 11 then

    ShowMessage('Numéro de matricule mal saisi')   else   begin     a1:= StrToInt(copy(s,1,1));     a2:= StrToInt(copy(s,2,1));     a3:= StrToInt(copy(s,3,1));     a4:= StrToInt(copy(s,4,1));     m1:= StrToInt(copy(s,5,1));     m2:= StrToInt(copy(s,6,1));     j1:= StrToInt(copy(s,7,1));

    j2:= StrToInt(copy(s,8,1));     n1:= StrToInt(copy(s,9,1));     n2:= StrToInt(copy(s,10,1));     nc:= StrToInt(copy(s,11,1));     sum := 5*a1+4*a2+3*a3+2*a4+7*m1+6*m2+5*j1+4*j2+3*n1+2*n2;     sum := sum mod 11;     if sum = 1 then s:='faux'     else     begin       if sum = 0 then c:= 0       else c:= 11-sum;       if nc=c then s:='correct'       else s:='faux';     end; :=s;   end; end; procedure TfrmMatricule.btnExitClick(Sender: TObject); begin

  Application.Terminate; end; end.

7.7.4      Explication du code

La variable s va contenir le numéro de matricule saisi. C’est la valeur saisie. 



Pour éviter qu’un utilisateur ne donne qu’une partie d’un numéro de matricule, nous faisons un test sur la longueur du numéro et nous affichons une erreur si la longueur ne correspond pas. 

Le message d’erreur est affiché par la procédure ShowMessage dont la syntaxe est la suivante :

ShowMessage(msg: string); où msg chaîne de caractères à afficher.

Ensuite nous extrayons les différentes valeurs du numéro de matricule. Comme toutes les valeurs saisies sont des caractères nous devons les transformer en entiers par la fonction StrToInt.

La fonction copy sert à extraire des parties de chaînes de caractères. Sa syntaxe est la suivante :

Copy(s, index, count: Integer): string; où :

S

chaîne de laquelle est extraite la partie ;

Index

indice de début de la chaîne à extraire (commence par 1) ;

Count

nombre de caractères à extraire.

Les étapes suivantes correspondent à l’algorithme énoncé.

Pour terminer nous éditons le résultat comme texte du champ edtResultat.

La procédure Tformulaire.btnExitClick sert de nouveau à arrêter l’application.

7.8 Une petite machine à calculer

Dans ce prochain exercice nous nous proposons de mettre en œuvre une petite machine à calculer, qui effectuera les 4 opérations élémentaires.

7.8.1      Présentation visuelle

Comme toujours il nous faut définir d’abord un formulaire. Voici une possibilité d’une telle interface entre l’opérateur et la machine. 

Nous appellerons, comme toujours Tformulaire l’objet que nous allons définir ci-dessous. 

Nom

type

text

caption

edtNum

TEdit

Saisie des nombres et des opérateurs qui interviennent dans le calcul

btnButton0

TButton

0

btnButton1

TButton

1

btnButton2

TButton

2

btnButton3

TButton

3

btnButton4

TButton

4

btnButton5

TButton

5

btnButton6

TButton

6

btnButton7

TButton

7

btnButton8

TButton

8

btnButton9

TButton

9

btnButtonclear

TButton

C

btnButtondiv

TButton

/

btnButtonequal

TButton

=

btnButtonminus

TButton

-

btnButtonmult

TButton

*

btnButtonplus

TButton

+

btnButtonarret

TButton

Stop

7.8.2      Code

Une possibilité de code pour cette machine à calculer est le suivant : 

unit Unit1;

 interface

 uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;

 type

  Tformulaire = class(TForm) edtNum: TEdit;     btnButton7: TButton;     btnButton1: TButton; btnButton9: TButton;     btnButton8: TButton;     btnButton6: TButton; btnButton5: TButton;     btnButton2: TButton;     btnButton4: TButton; btnButton3: TButton;     btnButton0: TButton;     btnButtonmult: TButton; btnButtondiv: TButton;     btnButtonclear: TButton;     bnButtonminus: TButton;     btnButtonplus: TButton;     btnButtonequal: TButton; btnButtonArret: TButton;     procedure FormCreate(Sender: TObject);     procedure btnButton0Click(Sender: TObject);     procedure btnButtonplusClick(Sender: TObject);     procedure bnButtonminusClick(Sender: TObject);     procedure btnButtonmultClick(Sender: TObject);     procedure btnButtondivClick(Sender: TObject);     procedure btnButtonclearClick(Sender: TObject);     procedure btnButtonequalClick(Sender: TObject);     procedure btnButtonArretClick(Sender: TObject);   private

    { Private declarations }   public

    { Public declarations }     flag, n1, n2, op : integer;     n3 : real;

  end;  var   formulaire: Tformulaire;

 implementation  

{$R *.dfm}  procedure Tformulaire.FormCreate(Sender: TObject); begin   flag:=1; end;  procedure Tformulaire.btnButton0Click(Sender: TObject); var strNum:string; begin if Sender=btnButton0 then strNum:='0' else   if Sender=btnButton1 then strNum:='1' else   if Sender=btnButton2 then strNum:='2' else   if Sender=btnButton3 then strNum:='3' else   if Sender=btnButton4 then strNum:='4' else   if Sender=btnButton5 then strNum:='5' else   if Sender=btnButton6 then strNum:='6' else   if Sender=btnButton7 then strNum:='7' else   if Sender=btnButton8 then strNum:='8' else   strNum:='9';

   if flag=0 then + strNum   else   begin :=strNum;     flag:=0   end; end;  procedure Tformulaire.btnButtonplusClick(Sender: TObject); begin

  n1:=strtoint();   flag := 1; op := 1; end;  procedure Tformulaire.bnButtonminusClick(Sender: TObject); begin   n1:=strtoint();   flag := 1;   op := 2; end;

procedure Tformulaire.btnButtonmultClick(Sender: TObject); begin n1:=StrToInt();   flag := 1;   op := 3; end;  procedure Tformulaire.btnButtondivClick(Sender: TObject); begin   n1:=StrToInt(); flag := 1;   op := 4; end;  procedure Tformulaire.btnButtonclearClick(Sender: TObject); begin   := '';   flag := 1; end;  procedure Tformulaire.btnButtonequalClick(Sender: TObject); begin n2:=StrToInt();   case op of     1: n3:=n1+n2;

    2: n3:=n1-n2;

    3: n3:=n1*n2;     4: n3:=n1/n2;   end;//case :=FloatToStr(n3);   flag := 1; end;

 procedure Tformulaire.btnButtonArretClick(Sender: TObject); begin

  Application.Terminate; end; end.

7.8.3      Explication du code

Les méthodes invoquées par les boutons 0...9 de la calculatrice étant similaires, on peut se servir d’une seule procédure (au lieu de dix !!) pour réagir à l’actionnement des différentes touches numériques.

Cette procédure commune étant définie uniquement pour l’événement btnButton0Click

« procedure Tformulaire.btnButton0Click(Sender : TObject) », les neuf autres touches numériques doivent donc produire le même événement. Pour cela, on choisira dans l’onglet « Events » de l’inspecteur d’objets la bonne procédure btnButton0Click.

Pour discerner la touche numérique qui a déclenché la procédure et ainsi donner la bonne valeur à la variable strNum, on compare le contenu de la variable Sender avec les noms des différentes touches numériques (if Sender = btnButton ... then ...).

Les mêmes variables flag, op, n1, n2 et n3 sont utilisées dans toutes les procédures, et sont donc déclarées dans l’en-tête du programme (variables globales).

La variable flagest initialisée à 0 lors du lancement du formulaire (événement FormCreate du formulaire). Si flag = 0, le chiffre correspondant à la touche numérique actionnée est concaténé à la chaîne de caractères se trouvant déjà dans .

Si par contre flag = 1, le chiffre correspondant à la touche numérique actionnée est copié dans tout en écrasant le contenu antérieur.

En cliquant sur un signe d’opération (+ , - , * , /), le contenu de la propriété Text de l’objet edtNum est copié dans la variable n1 et constitue le premier opérande. La variable op est initialisée avec le code correspondant à l’opération visée et la valeur 1 est assignée à la variable flag. Ainsi le chiffre suivant tapé sur les touches numériques de la calculatrice écrase le contenu de l’affichage (car flag = 1) et constitue le premier chiffre du deuxième opérande. La variable flag est alors remise à 0 et les chiffres suivants sont concaténés au deuxième opérande.

En tapant sur la touche ( = ), le contenu de la propriété Text de l’objet edtNum est copié dans la variable n2 et consitue le deuxième opérande. L’opération définie par le code contenu dans la variable op est alors effectuée à l’aide de la structure alternative à choix multiples (instruction case ... of ...).

Il reste à remarquer que la calculatrice ne respecte pas la priorité des opérations.

7.9 Calcul matriciel - utilisation du composant StringGrid

Le prochain programme que nous allons établir est un programme qui manipule les opérations sur les matrices carrées 2x2.

Exercice : 

Il est laissé au lecteur la possibilité de changer ce programme pour la manipulation des matrices carrées à 3 dimensions.

7.9.1      Le composant StringGrid

Dans cet exercice nous utilisons le type prédéfini : matrice ou StringGrid qui se trouve dans la barre des objets sous Additional. Il possède de nouvelles propriétés dont nous énumérons ici les plus importantes :

propriété

Type

explications

ColCount

Integer

nombre de colonnes

RowCount

Integer

nombre de lignes

FixedCols

Integer

nombre de colonnes d’en-têtes

FixedRows

Integer

nombre de lignes d’entêtes

DefaultColWidth

Integer

largeur des colonnes (pixels)

DefaultRowHeight

Integer

hauteur des colonnes (pixels)

Cells

ensemble de cellules

goEditing (Options)

Boolean

indique si l’utilisateur peut introduire des valeurs dans les cellules

Nous référençons une cellule par Cells[colonne,ligne]. 

Attention : nous devons faire attention que le comptage des lignes et des colonnes commence, comme si souvent, par 0.

7.9.2      Le composant ListBox

Dans cet exemple nous utilisons aussi un nouveau type, la ListBox. Elle sert à afficher plusieurs lignes de caractères et à donner la possibilité à l’utilisateur de choisir une ligne précise.

Nous trouvons la ListBoxdans la barre des composants standards. Trois propriétés sont importantes à relever : 

Propriété

type

explications

Items

string

tableau des lignes de la liste

ItemIndex

entier

indice de la ligne sélectionnée

Sorted

booléen

lignes triées ou non

7.9.3      Présentation visuelle

Commençons  d’abord, comme dans les exercices précédents, par établir un formulaire qui nous sert à saisir les données et à les afficher. Voici un exemple d’un tel formulaire.

Ce formulaire présente les composants suivants :

name

type

text

caption

lblTitre

TLabel

Calculs sur les matrices

lblEg1

TLabel

=

lblEg2



TLabel

=

lblInv

TLabel

inv

btnEff

TButton

effectuez

btnInv

TButton

inverse

btnArret

TButton

Stop

name

type

items

lbOp

TListBox

+ - *

name

type

colcount/rowcount

fixedcols/fixedrows

sgMat1

TStringGrid

2/2

0/0

sgMat2

TStringGrid

2/2

0/0

sgMat3

TStringGrid

2/2

0/0

sgMatInv

TStringGrid

2/2

0/0

sgMatRes

TStringGrid

2/2

0/0

Les composants de type StringGrid qui servent à introduire des matrices doivent avoir l’option goEditing avec la valeur True.

Le champ lbOp de type ListBoxsert à énumérer les différentes opérations et à donner à l’utilisateur la possibilité de choisir. 

Après l’élaboration de ce formulaire nous pouvons écrire le code nécessaire. Voici un exemple possible.

unit Unit1 ; interface uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, Buttons ;

 type

  Tformulaire = class(TForm) lblTitre : Tlabel ;     sgMat1 : TstringGrid ;     sgMat2 : TstringGrid ; sgMatRes : TstringGrid ;     sgMat3 : TstringGrid ;     sgMatInv : TstringGrid ;     lblEg1: Tlabel;     lblEg2: Tlabel;     lblInv: Tlabel;     lbOp: TlistBox;     btnEff: Tbutton;     btnInv: Tbutton;     btnArret: Tbutton;     procedure btnEffClick(Sender: Tobject);     procedure btnInvClick(Sender: Tobject);     procedure btnArretClick(Sender: Tobject);   private

    { Private declarations }   public

    { Public declarations }   end;//Tformulaire

 var   formulaire: Tformulaire;

 implementation {$R *.dfm} procedure Tformulaire.btnEffClick(Sender: TObject); var a,i,j : integer; begin   if lbOp.ItemIndex=0 then     for i:=0 to 1 do       for j:=0 to 1 do       begin         a:=StrToInt(sgMat1.Cells[i,j])+StrToInt(sgMat2.Cells[i,j]);         sgMatRes.Cells[i,j]:=IntToStr(a); end;       //j

    //i   //fi index=0   if lbOp.ItemIndex=1 then     for i:=0 to 1 do       for j:=0 to 1 do       begin         a:= StrToInt(sgMat1.Cells[i,j])-StrToInt(sgMat2.Cells[i,j]);         sgMatRes.Cells[i,j]:=IntToStr(a); end;       //j

    //i   //fi index=1   if lbOp.ItemIndex=2 then     for i:=0 to 1 do       for j:=0 to 1 do       begin

a:=StrToInt(sgMat1.Cells[0,j])*StrToInt(sgMat2.Cells[i,0])         +StrToInt(sgMat1.Cells[1,j])*StrToInt(sgMat2.Cells[i,1]); sgMatRes.Cells[i,j]:=IntToStr(a);       end;       //j

    //i   //fi index=0 end;//btnEffClick

 procedure Tformulaire.btnInvClick(Sender: TObject); var a,det:real; begin   det:=StrToInt(sgMat3.Cells[0,0])*StrToInt(sgMat3.Cells[1,1]) -StrToInt(sgMat3.Cells[1,0])*StrToInt(sgMat3.Cells[0,1]);   a:= 1/det*StrToFloat(sgMat3.Cells[1,1]);   sgMatInv.Cells[0,0]:=FloatToStr(a); a:= (-1/det)*StrToInt(sgMat3.Cells[1,0]); sgMatInv.Cells[1,0]:=FloatToStr(a);   a:= (-1/det)*StrToInt(sgMat3.Cells[0,1]);   sgMatInv.Cells[0,1]:=FloatToStr(a); a:= 1/det*StrToInt(sgMat3.Cells[0,0]);   sgMatInv.Cells[1,1]:=FloatToStr(a); end;//btnInvClick

procedure Tformulaire.btnArretClick(Sender: TObject); begin

  Application.Terminate end;//btnArret end.//Unit1

7.9.4      Explication du code

Comme les opérations +, - et * exigent deux opérateurs, mais que l’opération inverse n’a besoin que d’un seul, nous avons pu regrouper les trois premiers sous une seule procédure.

La  TListBox lbOpnous donne les valeurs suivantes : 

ItemIndex

opération

0

addition

1

soustraction

2

multiplication

Pour le reste, le contenu des différentes parties des procédures correspond aux règles mathématiques qui définissent les opérations sur les matrices.

8 La récursivité

8.1 Exemple

La fonction suivante calcule une puissance de base réelle non nulle et d’exposant naturel :

function puissance(x:real;m:integer):real; begin

  if m=0 then result:=1   else result:=x*puissance(x,m-1) end;

Cette fonction présente une grande différence par rapport à toutes les fonctions que nous avons définies précédemment. Dans la définition même on trouve déjà un appel à la fonction puissance. Il s’agit ici d’un mécanisme très puissant, présent dans tous les langages de programmation modernes : la récursivité. Le fonctionnement exact de ce mécanisme ainsi que les conditions d’utilisation seront étudiées en détail dans les paragraphes suivants. Remarquons cependant qu’il existe un lien étroit entre la récursivité en informatique et la récurrence en mathématique. La définition de la fonction puissance présentée ici est une transcription quasi directe des formules

??x0 =1           5 ?        , valables pour x non nul .

??xm = x?xm?1

8.2 Définition : « fonction ou procédure récursive » 

On dit qu’une fonction ou une procédure est récursive (de manière directe) si elle s’appelle elle-même. Une fonction ou une procédure est récursive de manière indirecte si elle appelle   une autre fonction ou procédure qui rappelle la première de façon directe ou indirecte.

La fonction puissance du paragraphe précédent est bien sûr une fonction récursive directe.

Le mécanisme de la récursivité est très puissant, mais il faut une certaine expérience pour pouvoir l’utiliser dans de bonnes conditions. Dans la suite nous allons élucider principalement les aspects suivants :

•   Sous quelles conditions et pourquoi une fonction récursive donne-t-elle le résultat attendu ? Comment vérifier qu’une telle fonction est correcte ?

•   Comment le système gère-t-il une fonction récursive ? C’est-à-dire comment est-ce que ce mécanisme fonctionne en pratique ?

•   Est-ce qu’une fonction récursive est « meilleure » ou « moins bonne » qu’une fonction itérative (normale) ?

Il est clair que ces différents aspects ne sont pas indépendants les uns des autres, mais qu’il faut une vue d’ensemble pour bien les comprendre.

5 La fonction «puissance» donne un résultat incorrect si x et m sont nuls. De plus, il est nécessaire que m soit un entier positif !

8.3 Etude détaillée d’un exemple

Dans ce paragraphe nous revenons à la fonction « puissance » de la page précédente et nous allons commencer par étudier quelques exemples d’exécution. puissance(7,0) : donne bien sûr comme résultat 1 vu que la condition m=0 est vérifiée.

puissance(7,1) : la condition m=0 n’est pas vérifiée et la fonction calcule donc d’abord «x*puissance(x,m-1)» c’est-à-dire «7*puissance(7,0)» ce qui donne dans une deuxième étape «7*1=7».

puissance(7,2) : ici la condition m=0 n’est pas non plus vérifiée et la fonction calcule donc aussi d’abord «x*puissance(x,m-1)» c’est-à-dire «7*puissance(7,1)» . Suivent ensuite les deux étapes précédentes. A la fin de la troisième étape le résultat obtenu est «7*puissance(7,1)=7*[7*puissance(7,0)]=7*7*1=49».

Il est important de remarquer ici que le système refait chaque fois toutes les étapes et « ne se souvient pas » des appels de fonctions précédents. L’exécution de puissance(7,12) nécessite 13 passages dans la fonction : d’abord 12 appels récursifs et ensuite un dernier passage où m=0.

L’exemple puissance(7,-2) est particulièrement intéressant. La condition m=0 n’est pas  vérifiée et la fonction calcule donc «x*puissance(x,m-1)» c’est-à-dire «7*puissance(7,-3)». Ensuite elle va évaluer «7*puissance(7,-4)», «7*puissance(7,-5)», «7*puissance(7,-6)», etc. Il est clair que cet appel ne va certainement pas donner le résultat 1/49. Mais la situation est plus grave, l’exécution de la fonction ne va pas donner de faux résultat, mais cette exécution ne va pas se terminer vu que la condition m=0 ne sera plus jamais vérifiée.

Pour qu’une fonction ou une procédure récursive s’arrête, il est nécessaire que le code vérifie les conditions suivantes :

Pour une ou plusieurs valeurs des données, appelées « cas de base », la fonction calcule directement (sans appel récursif) le résultat.

Dans le code de la fonction il doit être assuré que chaque suite d’appels récursifs va toujours finir par atteindre un cas de base.

Il est clair que le fait que la fonction s’arrête, signifie seulement qu’elle va fournir un résultat, mais non pas que ce résultat est correct. L’arrêt de la fonction est une condition préalable !

Dans notre exemple, il est donc nécessaire de préciser que la fonction « puissance » ne convient pas pour les exposants négatifs. 

Dans une démonstration par récurrence en mathématiques la situation est semblable : Pour montrer qu’une propriété est vraie pour tout entier naturel, on montre d’abord qu’elle est vraie pour le cas de base n=0 et ensuite on montre que si la formule est vraie pour le naturel n, alors elle reste vraie pour n+1. La véracité de la propriété pour n=4 est alors ramenée successivement à n=3, n=2, n=1 jusqu’au cas de base n=0, que l’on sait vérifié.

8.4 Fonctionnement interne

Dans ce paragraphe on va chercher une réponse à la question comment le système gère l’exécution d’une procédure récursive. La bonne compréhension de ce mécanisme est importante pour pouvoir rédiger des programmes efficaces.

Revenons à l’exemple de la fonction factorielle qui calcule la factorielle d’un nombre naturel donné. Cet exemple, déjà implémenté de façon itérative au chapitre précédent, se prête particulièrement bien à être programmé de façon récursive vu que la définition mathématique de la fonction se base sur des formules de récurrence.

?0!=1                                            ?0!=1

? ou bien ?

?n!= n?(n ?1)! si n? N0                         ?n!= n?(n ?1) (? n ? 2)?K?3?2?1 si n? N0

function factorielle(n:integer):integer; begin

if n=0 then result:=1 else result:=n*factorielle(n-1) end;

On peut l’intégrer dans le programme Delphi du chapitre précédent.



903