Le débutant face à C++Builder

Geronimo

Ce tutoriel est spécialement destiné aux débutants qui souhaitent apprendre à se servir de C++Builder avec de simples rudiments du C++, ce qui est tout à fait possible étant donné la facilité d'utilisation de cet environnement de développement.

Tous droits de reproduction réservés à l'auteur. L'auteur se dégage de toute responsabilité quant à l'utilisation directe ou indirecte de ce document.

Cette page a été testée sous Internet Explorer 6.0, Netscape 6.0, Konqueror et Mozilla.

- Titre : Le débutant face à C++Builder

- Auteur : Geronimo

- Parution : 1 mars 2003

- Mise à jour : 10 mars 2013

- Licence : Copyright ® 2013 Geronimo. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Les bases

- I-A. Prérequis

- I-B. Installation

- I-C. Premières remarques

- I-D. Premiers pas

- I-E. La programmation événementielle

- II. Un convertisseur euros/francs

- II-A. Spécifications de notre projet

- II-B. Premiers préparatifs

- II-C. Sauvegarde du projet

- II-D. Fenêtre

- II-D-1. Fiche

- II-D-2. Zone cliente

- II-D-3. Bloquer le redimensionnement

- II-E. Composants

- II-E-1. Les zones d'édition

- II-E-2. Les labels

- II-E-3. Les boutons

- II-F. La classe Fiche

- II-G. Contrôle de la saisie

- II-G-1. Gestionnaire d'événements commun à deux événements

- II-G-2. Contrôle de la saisie

- II-G-3. Constructeur de la fiche

- II-H. Conversion

- II-H-1. Exceptions

- II-H-2. Attribuer un gestionnaire d'événements dans le code

- II-I. Conclusion

I - Les bases

Cette première partie vous explique comment installer C++Builder et vous apprend les premières bases qui vous permettront de mieux comprendre la suite.

I-A - Prérequis

Ainsi que nous l'avons dit précédemment, la lecture de ce document ne nécessite que peu de connaissances. En effet, nous nous attacherons à décrire précisément les étapes suivies dans la conception de nos programmes, ainsi qu'à commenter le code utilisé, afin qu'il soit facilement compréhensible. Néanmoins, il est nécessaire que le lecteur ait une certaine connaissance du C++ (syntaxe, fonctions, base des pointeurs) afin de pouvoir suivre ce cours avec aisance.

Sur le plan matériel, ayez un ordinateur devant vous (allumé, bien sûr) ainsi que le logiciel Borland C++Builder. La version utilisée a peu d'importance, ayez au moins la version 4. Il se peut pourtant que certaines des fonctions décrites ne soient pas disponibles avec votre version.

Enfin, toute votre bonne volonté sera requise. Mais si vous avez commencé à lire, c'est que vous souhaitez probablement ne pas vous arrêter là.

I-B - Installation

L'installation de Borland C++Builder ne pose pas de problème. La procédure est automatisée et vous n'aurez aucun mal à la suivre. Deux choses sont cependant importantes à noter : tout d'abord, parmi les composants à installer, n'oubliez surtout pas d'installer l'aide de Borland C++Builder (qui est très bien faite, et à laquelle je vous recommande de vous référer) ainsi que l'aide de la SDK Microsoft qui est une source très complète d'informations. La seconde chose à signaler, c'est le choix du répertoire d'installation : par défaut, le répertoire proposé est C:\Program Files\Borland\CBuilder5. Je vous déconseille ce choix, tout d'abord parce qu'il est plus long à taper lorsque vous utiliserez la ligne de commande pour vous y rendre, ce qui arrivera probablement :

C:\Windows>

C:\Windows>cd ..

C:\>cd "Program Files\Borland\CBuilder5"

ou

C:\Windows>cd "c:\Program Files\Borland\CBuilder5"

De plus, certains programmes n'apprécient pas les espaces dans les noms de répertoires comme dans "Program Files". Bien sûr, certains me diront que cela ne leur est jamais arrivé, mais le jour où le problème survient… Choisissez donc plutôt C:\Borland afin que C++Builder soit installé dans C:\Borland\CBuilder5.

Il se peut que vous ayez différentes erreurs lors de l'installation. Je ne peux pas vraiment vous éclairer sur ce sujet, n'en ayant jamais eu, mais effectuez une petite recherche sur Google, par exemple, et vous devriez trouver votre bonheur.

Voilà ce qu'il y avait à dire sur l'installation de C++Builder.

I-C - Premières remarques

C++Builder est maintenant installé. Vous pouvez le démarrer grâce au raccourci placé dans le menu Démarrer de Windows. Personnellement, j'ai créé un raccourci sur le bureau ce qui me permet de le démarrer plus rapidement. Une image s'affichera pendant le chargement de C++Builder qui durera quelques secondes à une demi-minute selon la rapidité de votre machine. Nous verrons plus tard comment accélérer ce chargement.

Vous vous retrouvez alors devant un écran partagé en plusieurs zones, dont une barre d'outils, une zone d'édition et d'autres outils bizarres (que vous trouverez très rapidement pratiques). Vous remarquerez que C++Builder dispose de menus classiques tels Fichier ou Édition qui comportent toutes les fonctions que l'on a l'habitude de voir dans n'importe quel traitement de texte.

Cliquez donc sur Fichier puis Enregistrer Tout. C++Builder vous présentera alors une boite de dialogue proposant d'enregistrer le fichier courant sous le nom de Unit1.cpp. Créez un dossier nommé Test dans le répertoire C:\Borland et enregistrez-y le fichier sous le nom de Test1_main.cpp pour bien repérer que ce fichier est le fichier principal de votre projet. Validez. C++Builder vous propose maintenant d'enregistrer un nouveau fichier sous le nom de Project1.bpr. Un fichier .bpr est un fichier projet. Changez ce nom et nommez-le Test1.bpr.

Qu'est-ce qu'un fichier projet ?
Lorsque vous développez (ou développerez) correctement un logiciel assez volumineux, vous avez un certain nombre de fichiers, de bibliothèques qui doivent être tous liés ensemble. Ainsi, le fichier projet signale quels fichiers doivent être liés, quelles options doivent être passées au compilateur…

Avec l'explorateur, nous pouvons aller faire un petit tour dans le répertoire C:\Borland\Test qui contient quelques fichiers :

Ainsi, le fichier Test1.bpr a bien été créé, de même que le fichier Test1_main.cpp. Mais quels sont ces autres fichiers. Le fichier Test1.cpp est le fichier correspondant au fichier projet Test1.bpr. Le fichier Test1.cpp contient le code qui permettra à votre programme de démarrer, nous étudierons ce code plus tard. Le fichier Test1_main.cpp contient le code correspondant à la fiche (=fenêtre) principale. Cette fenêtre principale se construit facilement. Toutes les informations la concernant se trouvent dans le fichier Test1_main.dfm. On constate que C++Builder a également créé un fichier nommé Test1_main.h qui sera le fichier d'en-tête contenant toutes les déclarations correspondant à cette fiche principale.

I-D - Premiers pas

Revenons dans C++Builder, où nous nous trouvons face à une zone de texte qui contient du code que nous détaillerons plus tard, pour le moment, ce n'est pas très important.

La palette des composants est la barre d'outils divisée en onglets et remplie de petites icônes. Ces petites icônes représentent en général le composant, comme une zone d'édition, un menu…

Nous allons commencer par faire un programme tout simple, qui ne nous demandera de taper qu'une unique ligne de code. Appuyez sur la touche [F12]. Une fenêtre apparait, parsemée de petits points qui forment un réseau. Ces points n'apparaitront pas dans votre programme, ils sont juste là pour vous aider à positionner correctement les différents éléments qui formeront l'interface de votre programme. Vous pouvez redimensionner votre fenêtre afin qu'elle apparaisse plus petite à l'exécution. Double-cliquez ensuite sur l'icône représentant un bouton OK dans la palette des composants.

Vous pouvez vous aider de la petite bulle d'aide qui apparait et qui doit spécifier Button.

Si vous avez bien double-cliqué sur l'icône représentant un bouton, vous devez voir un bouton placé au milieu de la fenêtre. Ce bouton peut être déplacé par un simple "cliquer-trainer". Vous pouvez ainsi le positionner où vous le voulez. Vous pouvez également le redimensionner, mais sachez qu'il a la taille standard par défaut.

L'inspecteur d'objets
Chaque composant comme le bouton a des propriétés telles la taille, la hauteur, la légende (titre, caption), la police qu'il est possible de modifier grâce à l'inspecteur d'objets. Si l'inspecteur d'objets n'est pas affiché, pensez à l'afficher en cliquant successivement sur Voir, Inspecteur d'objets ou tout simplement en appuyant sur [F11]

Le bouton est par défaut intitulé Button1. Vous pouvez modifier cela en cliquant dans l'inspecteur d'objet à la ligne Caption et en modifiant le texte qui s'y situe. Parallèlement, le texte sera modifié sur le bouton dans la fenêtre. Modifiez le texte en Informations.

Nous allons également changer le nom du bouton. En effet, par défaut, il s'appelle Button1. Cela peut sembler simple, mais lorsque la fiche comporte une dizaine de boutons nommés Button1, Button2… Button10, il est plus difficile de s'y retrouver et de savoir qui fait quoi. Retournez dans l'inspecteur d'objets et modifiez-y la valeur de la propriété Name en la remplaçant par Informations_button.

Mais à quoi peut donc servir ce nom ? Il se trouve tout simplement que même si vous voyez le bouton comme un objet graphique dans une fenêtre, ce bouton est tout simplement une variable : retournez dans la zone d'édition et cliquez avec le bouton droit sur l'onglet Test1_main.cpp puis cliquez sur Ouvrir le fichier Source/En-tête. Voilà normalement ce que vous devez y voir :

//------------------------------------------------

#ifndef Test1_mainH
#define Test1_mainH
//------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//------------------------------------------------
class TForm1 : public TForm
{
__published:    // Composants gérés par l'EDI
TButton *Informations_button;
private:        // Déclarations utilisateur
public:         // Déclarations utilisateur
__fastcall TForm1(TComponent* Owner);
};
//------------------------------------------------
extern PACKAGE TForm1 *Form1;
//------------------------------------------------
#endif

Vous remarquerez rapidement à la ligne 14 le code TButton *Informations_button. Informations_button est bien le nom de notre bouton et tout simplement une variable. Cela permet d'introduire la notion de RAD : lorsque vous avez placé le bouton sur la fiche, vous l'avez fait rapidement. Et vous n'avez pas eu à placer le code déclarant cette variable pointeur Informations_button ; cela s'est fait tout seul. C++Builder crée donc le code pour vous afin que vous ne perdiez pas de temps à coder des lignes qui relèvent de la routine et non véritablement de la conception du projet.

Nous allons maintenant écrire une ligne de code afin que notre programme fasse quelque chose. Si vous le compilez et l'exécutez maintenant, vous auriez seulement un bouton sur une fenêtre et le clic sur ce bouton ne donnerait aucun résultat. (Vous pouvez essayer pour voir, appuyez sur [F9]. Après quelques secondes, le programme se lance ; fermez-le ensuite.)

La ligne de code que nous allons écrire va permettre d'afficher une petite boite de message avec quelques informations lors d'un clic sur le bouton Informations_button. Revenez à la fiche en appuyant sur [F12] et double-cliquez sur le bouton. La zone d'édition contient maintenant en plus le code suivant :

//---------------------------------------------------------------------------

void __fastcall TForm1::Informations_buttonClick(TObject *Sender)

{

}

//---------------------------------------------------------------------------

Ce code est la fonction Informations_buttonClick qui appartient à la classe TForm1. Si vous ne comprenez pas cela, ce n'est pas très grave, nous en parlerons très probablement plus tard. Ajoutez donc dans cette fonction la ligne de code suivante :

ShowMessage("Informations\nLogiciel développé par Toto, (c) 2002");

Votre fonction ressemble donc maintenant à ceci :

//---------------------------------------------------------------------------

void __fastcall TForm1::Informations_buttonClick(TObject *Sender)

{

ShowMessage("Informations\nLogiciel développé par Toto, (c) 2002");

}

//---------------------------------------------------------------------------

Cette simple ligne permet d'afficher un message dans une petite fenêtre. Appuyez sur [F9] et cliquez sur le bouton.

I-E - La programmation événementielle

En apprenant le C++, vous avez sûrement créé de petits programmes où des lignes de code se succédaient et s'exécutaient dans l'ordre. Ici, rien de tel. On dirait que tout marche tout seul… C'est le principe de la programmation événementielle que vous avez mis en œuvre avec cette simple petite ligne de code : vous avez posé un bouton sur votre fiche et lorsque vous cliquez dessus, une fonction est appelée. Cette fonction est donc nommée le gestionnaire d'événements OnClick du bouton, car elle réagit à l'événement "Quand on clique sur le bouton Informations_button" (=OnClick) d'où son nom automatiquement attribué par C++Builder : Informations_buttonClick. Nous allons voir cela plus clairement : appuyez sur [F12] pour afficher la fiche puis cliquez sur le bouton Informations_button pour le sélectionner. Regardez maintenant dans l'inspecteur d'objets. Vous pouvez y voir toutes les propriétés du bouton ; en haut, vous remarquerez l'onglet Événements ; cliquez dessus. Vous voyez alors la liste des événements possibles pour notre bouton, avec bien évidemment, en face de l'événement OnClick notre fonction Informations_buttonClick. Notre fonction est donc bien attribuée pour gérer l'événement OnClick. Regardez la liste, vous y remarquerez l'événement OnKeyPress qui est déclenché si jamais une touche est pressée sur le bouton. Double-cliquez dans la zone correspondante, et la fonction gestionnaire d'événements OnKeyPress sera créée. Le code suivant est ajouté dans votre zone d'édition :

void __fastcall TForm1::Informations_buttonKeyPress(TObject *Sender,

char &Key)

{

}

//---------------------------------------------------------------------------

Nous allons alors y placer une ligne de code :

ShowMessage("Vous avez appuyé sur une touche et non cliqué sur le bouton");

Lancez le programme et appuyez sur une touche (remarque : évitez la touche Entrée et Espace qui sont d'une certaine manière considérées, comme Windows, comme des clics) : la boite de dialogue correspondante sera affichée.

Vous avez également appris qu'un programme commence toujours par une fonction main ; c'est peut-être pour cela que vous trouvez ce genre de programmation un peu bizarre. Et bien rassurez-vous, nous allons retrouver la fonction main. Cliquez donc sur le menu Projet puis sur Voir la source. Le fichier Test1.cpp est ouvert :

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

USERES("Test1.res");

USEFORM("Test1_main.cpp", Form1);

//---------------------------------------------------------------------------

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

try

{

Application->Initialize();

Application->CreateForm(__classid(TForm1), &Form1);

Application->Run();

}

catch (Exception &exception)

{

Application->ShowException(&exception);

}

return 0;

}

//---------------------------------------------------------------------------

Et voilà, nous trouvons la fonction WinMain (l'équivalent pour Windows de la fonction main). Cette fonction contient le code qui permet de faire démarrer le programme. C++Builder ne présente pas ce fichier directement, car on se sert rarement de la fonction WinMain, sauf dans certains cas. Nous n'allons pas détailler les blocs try et catch ; sachez seulement que si une exception (erreur grave comme la division par zéro) se produit dans le bloc try, il est possible de la gérer dans le bloc catch. Ici, l'erreur sera signalée (Application->ShowException(&exception);). Ce qui nous intéresse le plus pour le moment, c'est le code contenu dans le bloc try. Tout d'abord, Application->Initialize. Cette instruction initialise tout simplement l'application. L'instruction Application->CreateForm(__classid(TForm1), &Form1); permet de créer la fiche Form1, sur laquelle nous avons posé le bouton. Enfin, l'instruction Application->Run(); lance le programme en affichant la première fiche créée. Ici la question ne se pose pas étant donné que la seule fiche créée est Form1.

La syntaxe X->Y comme dans Application->Initialize
Vous connaissez sûrement la syntaxe X.Y qui permet "d'atteindre" le membre Y d'une structure (ou d'une classe) X avec X qui est une instance de la classe T. La syntaxe -> (flèche) permet d'atteindre le membre Y d'une structure (ou classe) X avec X qui est un pointeur sur une instance de la classe T. Voici deux exemples :

class Donnees

{

int longueur, largeur, hauteur;

};

Donnees Donnee1;

Donnee1.longueur = 3;

// -------------------------------------

Donnees *Donnee2;

Donnee2 = new Donnees;

Donnee2->longueur = 10;

II - Un convertisseur euros/francs

Dans la première partie, nous avons étudié les premières bases de C++Builder. Dans cette seconde partie, nous allons construire un petit programme, extrêmement simple : un convertisseur euros/francs. Cela va nous permettre, au travers d'un exemple simple, d'étudier d'autres fonctions et de vous présenter d'autres concepts de C++Builder.

II-A - Spécifications de notre projet

Avant de commencer tout projet, il faut se demander quelles vont être les fonctionnalités intégrées au logiciel pour bien tout préparer. Pourquoi ? La structure de votre code va dépendre des fonctions que vous souhaiterez mettre à disposition dans votre programme et ne pas y penser à l'avance, c'est risquer d'avoir à repenser cette structure en cours de route, ce qui est souvent très difficile à faire. Évidemment, cela n'est pas aussi vrai pour un petit projet comme notre Eurolette, mais mieux vaut tout de suite prendre les bonnes habitudes. Notre convertisseur doit être conçu de la manière suivante :

- deux zones : l'une où on tape le montant en francs. L'autre où le montant est entré en euros ;

- une conversion "à la volée" : le montant tapé dans une devise est automatiquement converti dans l'autre ;

- donc une validation "à la volée" pour éviter que l'utilisateur rentre n'importe quels caractères.

II-B - Premiers préparatifs

Créez un nouveau projet à l'aide du menu Fichier/Nouvelle Application. La première chose à faire est de changer le titre de l'application. Le titre de l'application est le texte qui apparaitra dans la barre des tâches. Pour cela, cliquez sur Projet/Options, puis sur l'onglet Application. Dans le champ Titre, choisissez le titre de votre application. Nous pouvons entrer Eurolette. Vous pouvez également changer l'icône du programme en cliquant sur le bouton Icône et en sélectionnant un fichier .ico dans votre arborescence.

Ensuite, validez et revenez dans la fenêtre principale de l'IDE. Commencez par changer également la taille de la fenêtre. Pour cela, allez dans l'inspecteur d'objets et modifiez la propriété Caption de la fiche. Entrez également Eurolette. Le titre de la fiche est celui qui apparait dans la barre de titre de la fenêtre.

II-C - Sauvegarde du projet

Pensez à sauvegarder tout de suite le projet grâce à Fichier/Tout Enregistrer. Au lieu de sauvegarder le fichier source sous Unit1.cpp, nous le sauvegarderons sous FichePrincipale.cpp et au lieu de sauvegarder le projet sous Project1.bpr, nous le sauvegarderons sous Eurolette.bpr.

II-D - Fenêtre

II-D-1 - Fiche

Avec C++Builder, la fenêtre est en général appelée fiche lors de la conception ; en effet, une fiche pourra soit être une fenêtre, soit une boite de dialogue, mais la conception reste identique dans les deux cas, et fenêtres et boîtes de dialogue sont donc représentées par une même classe : la classe TForm.

II-D-2 - Zone cliente

La zone cliente est la zone de la fenêtre située sous la barre de titre et comprenant tout le reste de la fenêtre. Pratiquement, c'est la zone où vous pouvez placer des composants, écrire du texte, etc.

Notre convertisseur euros/francs n'a pas besoin d'une grande zone cliente. Nous avons juste besoin d'afficher deux zones d'édition et le résultat de la conversion. Affichez donc la fenêtre ([F12]) et réduisez celle-ci.

II-D-3 - Bloquer le redimensionnement

Pour des raisons d'esthétique, il est même nécessaire d'empêcher l'agrandissement de la fenêtre. L'utilisateur ne doit pas pouvoir agrandir la fenêtre, ni la rétrécir, ce serait ridicule et amènerait des affichages quelque peu perturbés. Passez donc dans l'inspecteur d'objets et cliquez sur le petit + à gauche de la propriété Constraints. Allez ensuite à la propriété Width, et copiez son contenu dans les "sous-propriétés" MaxWidth et MinWidth de Constraints. Faites de même avec la propriété Height. La taille minimum et la taille maximum étant la même, l'utilisateur ne pourra donc ni agrandir ni rétrécir la fenêtre, ce qui est le but recherché.

La fenêtre est maintenant bien préparée.

II-E - Composants

Un composant est un élément que l'on peut placer sur la fiche et qui regroupent les fonctionnalités suivantes :

- propriétés :des variables que l'on peut changer et qui permettent de modifier le comportement du composant ;

- méthodes :des fonctions associées au composant qui permettent d'interagir avec lui ;

- événements :des notifications déclenchées par le composant, pour effectuer des actions en fonction de son comportement.

Le composant est très pratique, car il a un aspect visuel, ce qui permet d'accélérer le temps de développement, en évitant d'écrire des lignes de code inutiles. Cependant, il faut noter qu'un composant peut être utilisé à partir du code (et c'est souvent nécessaire) et que le composant lui-même n'est autre qu'une classe C++.

Un composant peut être de deux types :

- composant visuel, qui est un élément qui sera visible par l'utilisateur ;

- composant non visuel, qui sert pendant la conception, mais que l'utilisateur ne verra pas.

Notre petit logiciel va utiliser trois composants :

- des zones d'édition : une pour taper le montant en euros, l'autre pour taper le montant en francs ;

- des labels pour afficher justement le titre des zones d'édition ;

- un bouton pour pouvoir quitter.

II-E-1 - Les zones d'édition

La zone d'édition est le composant que vous pouvez voir un peu partout, dès qu'il s'agit d'entrer des informations, par exemple, les formulaires sur Internet contiennent presque toujours des zones d'édition.

Placez maintenant deux zones d'édition sur la fiche. Pour cela, double-cliquez deux fois de suite sur l'icône Edit de la barre des composants.

Déplacez les composants Edit sur la fiche pour obtenir une disposition agréable. Maintenant que nous avons ajouté deux composants, la première chose à faire est de les renommer avec des noms cohérents par rapport à leur utilisation. Sélectionnez le composant Edit1, cliquez dessus et modifiez la propriété Name en EuroZone. Faites de même avec l'autre, en le nommant FrancZone. Renommer les composants est extrêmement important, afin de ne pas perdre de temps par la suite à se demander à quoi sert tel composant. Là encore, ce n'est pas très grave pour un petit projet comme le le nôtre, mais autant prendre les bonnes habitudes dès le début. Profitez-en pour effacer le contenu de la propriété Text, qui contient par défaut le nom du composant, mais comme nos zones d'édition ne doivent contenir que des nombres, il n'est pas bon d'y laisser du texte.

II-E-2 - Les labels

Un label est tout simplement un composant permettant d'ajouter du texte dans une boite de dialogue, ce texte servant en général à expliciter l'utilisation de tel ou tel élément.

Placez maintenant deux composants Label.

Vous pouvez changer leur nom, mais cela a beaucoup moins d'importance étant donné que nous n'utiliserons jamais ce nom par la suite. Modifiez leur propriété Caption, toujours grâce à l'inspecteur d'objets, et entrez-y respectivement Francs pour l'un, et Euros pour l'autre. Placez-les en face des zones d'édition correspondantes.

II-E-3 - Les boutons

Placez un Button sur votre fiche.

Modifiez sa propriété Name en QuitterButton. Modifiez sa propriété Caption en Quitter.

La conception graphique de notre petit logiciel est donc terminée. Nous allons maintenant aborder la phase de codage.

II-F - La classe Fiche

Nous allons ici gérer l'événement OnClick du bouton QuitterButton. L'événement OnClick est celui le plus couramment utilisé avec C++Builder : il est déclenché dès qu'un utilisateur clique sur un composant. Ici, nous devons quitter l'application dès que l'utilisateur clique sur le bouton Quitter.

Sélectionnez le bouton, et dans l'inspecteur d'objets, passez dans l'onglet Événements. Double-cliquez dans la zone située à droite de l'événement OnClick. Vous constatez alors qu'une fonction est immédiatement créée dans le code C++. Cette fonction sera systématiquement appelée dès que l'utilisateur cliquera sur le bouton. Vous pouvez voir son nom mentionné maintenant dans l'inspecteur d'objets, à côté de l'événement OnClick.

void __fastcall TForm1::QuitterButtonClick(TObject *Sender)

{

}

Nous allons ici détailler les différentes parties de l'en-tête de cette fonction :

- void, car la fonction ne renvoie aucune valeur ;

- fastcall : c'est une convention d'appel, spécifique à C++Builder, qui permet d'accélérer le traitement des fonctions, car les trois premiers paramètres passés à la fonction sont placés dans les registres du processeur (petites mémoires à accès extrêmement rapide).

- TForm1:: : cela signifie que la fonction créée appartient à la fiche Form1 ; cette fiche est représentée par la classe TForm1, définie dans le fichier FichePrincipale.h. En fait, chaque fiche que vous créez sera une nouvelle classe (et non une nouvelle instance de classe), qui comportera comme membres des pointeurs sur des objets : les composants. Appuyez sur Ctrl+[F6] et vous verrez le code suivant apparaître :

//---------------------------------------------------------------------------

#ifndef FichePrincipaleH

#define FichePrincipaleH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

//---------------------------------------------------------------------------

class TForm1 : public TForm

{

__published:    // Composants gérés par l'EDI

TEdit *FrancZone;

TEdit *EuroZone;

TLabel *Label1;

TLabel *Label2;

TButton *QuitterButton;

private:        // Déclarations utilisateur

public:         // Déclarations utilisateur

__fastcall TForm1(TComponent* Owner);

};

//---------------------------------------------------------------------------

extern PACKAGE TForm1 *Form1;

//---------------------------------------------------------------------------

#endif

- QuitterButtonClick(TObject *Sender) est tout simplement le prototype de la fonction.

C++Builder a donc automatiquement créé la fonction qui sera appelée lors d'un clic sur le bouton QuitterButton. Il nous faut donc écrire dans cette fonction le code permettant de quitter le programme. Il s'agit tout simplement d'un appel à la méthode Close() de la classe TForm1 :

void __fastcall TForm1::QuitterButtonClick(TObject *Sender)

{

Close();

}

Vous remarquerez deux choses :

- cette fonction est bien une méthode de la classe TForm1. Simplement, rappelez-vous que la fonction QuitterButtonClick dans laquelle nous tapons ce code est elle-même une fonction membre de la classe TForm1. Il ne faut donc pas préciser l'instance de la classe pour laquelle nous voulons effectuer l'action, donc ne pas écrire Form1->Close().
Il faut en effet bien faire la distinction entre Form1 et TForm1. TForm1 est la classe elle-même. Form1 est une instance de la classe TForm1, une copie en mémoire, de TForm1. Form1 a un nom presque semblable, c'est tout simplement parce que TForm1 ne doit avoir normalement qu'une seule instance, mais ce n'est pas obligatoire ;

- si vous regardez la définition de la classe TForm1 du fichier FichePrincipale.h, vous ne verrez pas la déclaration de la méthode Close, en effet, cette fonction est déclarée dans la classe TForm, mais n'oubliez pas que TForm1 hérite de toutes les propriétés de TForm, donc de la méthode Close.

N'oubliez pas que vous pouvez régulièrement tester le programme en le compilant et l'exécutant avec [F9]. Il nous reste maintenant à voir comment effectuer le contrôle de la saisie.

II-G - Contrôle de la saisie

Notre programme permet à l'utilisateur d'effectuer des conversions d'euros en francs. Cependant, rien n'empêche celui-ci de rentrer, volontairement ou non, autre chose que des chiffres dans la zone de texte. Nous avons deux solutions pour gérer ce problème :

- nous pouvons laisser l'utilisateur entrer n'importe quels caractères, et dans la fonction effectuant la conversion, nous demandons l'affichage d'un message d'erreur ;

- ou alors nous empêchons complètement l'utilisateur de rentrer des caractères invalides. C'est cette deuxième solution que nous préférerons, qui est beaucoup plus "propre" que l'autre.

Le contrôle que nous voulons effectuer est le suivant :

- l'utilisateur ne peut rentrer que des caractères numériques de 0 à 9.

II-G-1 - Gestionnaire d'événements commun à deux événements

Sélectionnez les deux zones d'édition EuroZone et FrancZone. Pour cela, maintenez la touche MAJ enfoncée tout en cliquant sur l'un, puis l'autre. Affichez l'onglet Événement de l'inspecteur d'objets. En face de l'événement OnKeyPress, tapez ZoneKeyPress et tapez Entree.

Cela crée la fonction ZoneKeyPress qui sera appelée pour l'événement OnKeyPress de ces deux zones d'édition. L'événement OnKeyPress est déclenché dès que l'utilisateur appuie sur une touche, mais avant que le contenu du composant soit modifié. Cela permet de contrôler la modification du contenu.

II-G-2 - Contrôle de la saisie

Nous allons donc contrôler quelle touche est enfoncée dans cet événement, et si une touche interdite est enfoncée, nous ferons croire au système qu'aucune touche n'a été enfoncée. Le code correspondant est extrêmement simple. Il prend place dans la fonction ZoneKeyPress créée ci-dessus :

void __fastcall TForm1::ZoneKeyPress(TObject *Sender, char &Key)

{

if ((Key < 48 || Key > 57)

&& Key != VK_BACK

&& Key != VK_DELETE

&& Key != DecimalSeparator)

Key = 0;

}

Le gestionnaire d'événements OnKeyPress utilise le paramètre char &Key qui est une référence à la variable Key contenant le code de la touche pressée. L'avantage de ce paramètre est qu'il est passé par référence donc il peut être modifié. On peut donc modifier cette valeur et pour tous les événements suivants, la touche enfoncée sera la nouvelle valeur. Nous pouvons aussi attribuer 0 à cette variable, dans ce cas, l'événement suivant n'aura pas la trace d'un appui sur une touche.

La condition est vraie si la touche enfoncée ne correspond pas à un chiffre Key < 48 || Key > 57. En effet, le caractère '0' a pour code 48, '1' a pour code '49' et ainsi de suite jusqu'à '9' (57). Il faut également que la touche ne soit ni retour arrière, ni [Suppr], et ni DecimalSeparator. DecimalSeparator est une variable globale qui contient le code du caractère séparateur des décimales ('.' ou ','). Mais dans notre cas, nous attribuerons à DecimalSeparator la valeur '.' pour éviter tout problème et pour des raisons de simplicité : le '.' est situé sur le pavé numérique, donc est plus facile à atteindre. Si toutes ces conditions sont vérifiées, la touche ne fait pas partie des touches autorisées donc nous lui attribuons 0.

II-G-3 - Constructeur de la fiche

Comme nous l'avons dit, DecimalSeparator se voit attribuer la valeur '.', nous effectuons cela dans le constructeur de la fiche pour être sûr que cela soit fait au tout début. Le constructeur de la fiche est présent dans le fichier FichePrincipale.cpp, tout en haut. Il est toujours créé automatiquement par C++Builder. Voici à quoi il doit maintenant ressembler :

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

DecimalSeparator = '.';

}

N'oubliez pas que le constructeur de la fiche est toujours le constructeur de la classe Fiche TForm1. Comme pour toute classe C++, c'est la fonction qui est appelée lors de la création d'une instance de la classe en mémoire, dans laquelle il est judicieux d'effectuer toutes les initialisations.

II-H - Conversion

Nous allons écrire ici deux fonctions dont le but est d'effectuer les conversions d'euros en francs et de francs en euros. Ces fonctions seront exécutées dès qu'une modification aura lieu dans l'une des deux zones d'édition. Nous allons donc écrire les fonctions gestionnaires d'événement OnChange de chacune des zones d'édition. Bien sûr, il serait possible d'écrire une seule fonction pour les deux zones, mais ici, le gain en concision serait ridicule par rapport à l'ampleur du projet.

Sélectionnez chacune des deux zones d'édition et double-cliquez en face de l'événement OnChange. Vous allez ainsi créer deux fonctions, FrancZoneChange et EuroZoneChange.

Voici le code correspondant au contenu de ces fonctions :

void __fastcall TForm1::FrancZoneChange(TObject *Sender)

{

double valeur = 0;

try { // L'exception sera déclenchée si le contenu de

// la zone est vide

valeur = StrToFloat(FrancZone->Text);

}

catch(...)

{

// On ne fait rien, c'est le but recherché

}

valeur /= 6.55957;

// On supprime la gestion de l'événement OnChange pour la

// zone d'édition cible

EuroZone->OnChange = 0;

EuroZone->Text = EuroZone->Text.FloatToStrF(valeur, AnsiString::sffFixed, 15, 2);

// On restaure la gestion de l'événement OnChange

EuroZone->OnChange = EuroZoneChange;

}

void __fastcall TForm1::EuroZoneChange(TObject *Sender)

{

double valeur = 0;

try { // L'exception sera déclenchée si le contenu de

// la zone est vide

valeur = StrToFloat(EuroZone->Text);

}

catch(...)

{

// On ne fait rien, c'est le but recherché

}

valeur *= 6.55957;

// On supprime la gestion de l'événement OnChange pour la

// zone d'édition cible

FrancZone->OnChange = 0;

FrancZone->Text = FrancZone->Text.FloatToStrF(valeur, AnsiString::sffFixed, 15, 2);

// On restaure la gestion de l'événement OnChange

FrancZone->OnChange = FrancZoneChange;

}

Le fonctionnement des fonctions est le même. Nous allons ici étudier la fonction FrancZoneChange. On essaie tout d'abord de convertir le contenu de la zone d'édition en flottant ; en effet, nous voulons pouvoir effectuer des conversions sur ce contenu et le calcul numérique est bien entendu impossible sur du texte ! La fonction StrToFloat que nous utilisons ici prend tout simplement un texte en paramètre (ici, le contenu de la zone d'édition qui vient d'être modifiée : FrancZone->Text) et retourne la valeur flottante correspondante. Mais si le contenu du texte est incorrect,

II-H-1 - Exceptions

Le C++ permet de gérer certaines erreurs en récupérant des exceptions. Ici, nous avons auparavant créé une fonction contrôlant les entrées donc nous ne devrions pas avoir de problème. En fait, il en reste un : si la zone est vide, la fonction StrToFloat échouera et déclenchera une exception. Dans ce cas, nous ne voulons surtout pas qu'un message s'affiche, comme c'est souvent le cas lors d'une exception, mais nous souhaitons tout simplement que rien ne se passe. Ainsi, si la fonction échoue, nous ne faisons rien (le bloc catch est vide). La variable valeur que nous utilisons par la suite dans les calculs est initialisée à 0 au début de la fonction, donc la conversion fonctionnera correctement et donnera 0 comme résultat.

II-H-2 - Attribuer un gestionnaire d'événements dans le code

La ligne de code suivante effectue évidemment la conversion, en prenant pour base 1 € = 6,55957 F.

Ensuite, vous remarquerez l'instruction EuroZone->OnChange = 0. Nous allons à la ligne suivante modifier le contenu de EuroZone. Mais si nous modifions ce contenu, la fonction EuroZoneChange sera appelée, puisque le contenu de EuroZone aura changé... et de même EuroZoneChange modifiera FrancZone, donc la fonction FrancZoneChange sera appelée. Vous comprenez bien que nous risquons de nous retrouver avec un comportement bizarre. L'instruction EuroZone->OnChange = 0 permet de résoudre ce problème : nous désactivons le gestionnaire d'événements OnChange de la zone d'édition EuroZone. De cette manière, nous pouvons à la ligne d'après effectuer la conversion EuroZone->Text = EuroZone->Text.FloatToStrF(valeur, AnsiString::sffFixed, 15, 2), et une fois celle-ci effectuée, nous pouvons réactiver le gestionnaire d'événements OnChange de la zone EuroZone en lui attribuant la fonction correspondante : EuroZone->OnChange = EuroZoneChange.

En fait, nous avons fait dans le code ce que nous avions fait précédemment dans l'inspecteur d'objets. La classe représentant la zone d'édition contient des membres, qui sont des pointeurs sur des fonctions. Le membre OnChange de la classe TEdit (zone d'édition) est un pointeur sur une fonction. Si nous attribuons une fonction à ce pointeur, elle sera appelée dès que le contenu de la zone d'édition sera modifié. Si nous lui attribuons 0, aucune fonction ne sera appelée. Nous avons donc joué sur ce principe pour éviter le petit problème qui se posait.

EuroZoneChange fonctionne exactement de la même manière.

II-I - Conclusion

Notre petit programme est fini. Vous pouvez le tester en l'exécutant avec [F9]. En ce qui concerne le contrôle de la saisie, nous aurions pu utiliser le composant MaskEdit, qui peut effectuer des contrôles. Mais il fallait que cette seconde partie vous montre le fonctionnement du composant Edit, composant le plus basique, mais peut-être le plus utile de la VCL.