I. Généralités▲
I-A. Familles de conversions▲
Les familles de conversion prises en charge en standard par Delphi 6 sont les suivantes :
- les distances (ex. : micromicron, mètre, mille nautique, pica, inch, etc.) ;
- les aires (ex. : are, hectare, mètre carré, yard carré, inch carré, etc.) ;
- les volumes (ex. : décimètre cube, hectomètre cubes, millilitre, décilitre, gallon, etc.) ;
- les masses (ex. : nanogramme, hectogramme, grain, pound, etc.) ;
- les températures (ex. : Celsius, kelvin, Fahrenheit, Réaumur, etc.) ;
- le temps (ex. : milliseconde, minute, semaine, décades, date julienne, etc.).
Le nombre d'unités de mesure déclaré par famille est non négligeable, il y a de fortes chances que vous découvriez pour la première fois un bon nombre de termes scientifiques…
I-B. Types de conversions▲
Un type de conversion est un sous-élément d'une famille de conversion.
Le micromicron, le mètre sont des types de conversion de la famille des distances.
Le nanogramme et le grain le sont aussi pour la famille des masses.
I-C. Modes de conversions▲
On distingue deux modes de conversion :
- la conversion simpleLa conversion simple ;
- la conversion procéduraleLa conversion procédurale.
I-C-1. La conversion simple▲
La conversion simple s'appuie sur un facteur numérique. Exemple 1 miles = 1609,344 mètres donc la conversion s'effectue avec un facteur multiplicateur de 1,609344.
Nous allons créer une application permettant de convertir des mètres en miles et inversement.
Posez sur une form deux champs TLabeledEdit (onglet Supplément) qui nous permettront de saisir les valeurs, un pour les mètres et un pour les miles (fig. 1).
Dans la clause uses section implémentation de votre fiche, indiquez que vous utiliserez l'unité unités ConvUtils et StdConvs.
implementation
uses
ConvUtils, StdConvs;
ConvUtils implémente les routines utilitaires de conversion, et StdConvs déclare les familles et types de mesures les plus courants (distances, températures, aires, volumes, etc.) accompagnés des facteurs multiplicateurs de conversion respectifs.
Nous allons implémenter les conversions Mètres <-> Miles dans les gestionnaires d'événement OnKeyDown des TLabeledEdit en interceptant la touche [Entrée].
procedure
TfrmMetresMiles.edMetresKeyDown(Sender: TObject; var
Key: Word
; Shift: TShiftState);
var
metres, miles: Double
;
begin
if
Key = VK_RETURN then
begin
metres := StrToFloat(edMetres.Text);
// Exécution de la conversion
miles := Convert(metres, duMeters, duMiles);
edMiles.Text := FloatToStr(miles);
end
;
end
;
La fonction globale Convert se charge de la conversion en spécifiant la valeur à convertir suivie des unités de mesure source et destination. Elle est déclarée dans l'unité ConvUtils comme suit :
function
Convert(const
AValue: Double
; const
AFrom, ATo: TConvType): Double
;
Le résultat est de type Double. Elle attend en paramètre :
- la valeur à convertir (de type Double) ;
- le type de l'unité de mesure de la valeur à convertir (exemple : duMeters pour Mètres) ;
- le type de l'unité de mesure résultat (exemple : duMiles pour Miles).
Pour réaliser la conversion inverse, implémentez le gestionnaire OnKeyDown du TLabeledEdit respectif aux Miles, et appelez la routine de conversion Convert en inversant les types d'unités de mesure pour les paramètres AFrom et ATo :
Pour convertir des mètres en miles, nous avions la ligne de code suivante :
miles := Convert(metres, duMeters, duMiles);
On implémente l'opération inverse dans le gestionnaire OnKeyDown du TLabeledEdit respectif à la saisie des miles :
metres := Convert(miles, duMiles, duMeters);
Avantage de l'opération : nous avons réalisé une conversion de valeur entre deux unités de mesure à l'aide d'une seule ligne de code sans se soucier des unités ni des facteurs de conversion.
Jusqu'à présent, nous avons vu des conversions mettant en jeu une seule famille de conversions, les distances. Mais plusieurs cas existent où deux familles interviennent dans la mesure. Par exemple, les kilomètres/heure, les litres/minute, etc.
Nous allons ajouter des éléments à notre application (fig. 2) de façon à calculer une conversion d'un temps exprimé en secondes pour parcourir une distance en mètres, et obtenir la vitesse correspondante en kilomètres par heure :
43"18 est le record du monde du 400 m plat détenu par Michaël Johnson (1999 - Séville).
Dans le code, nous allons intercepter la touche Entrée sur le TLabeledEdit de saisie du temps, et implémenter la conversion :
procedure
TfrmMetresMiles.edTempsKeyDown(Sender: TObject; var
Key: Word
; Shift: TShiftState);
var
distance, temps, vitesse: double
;
begin
if
Key <> VK_RETURN then
exit;
distance := StrToFloat(edDistance.Text);
temps := StrToFloat(edTemps.Text);
// La vitesse est exprimée en m/s et convertie en km/h
vitesse := Convert(distance/temps, duMeters, tuSeconds, duKilometers, tuHours);
edVitesse.Text := FloatToStr(vitesse);
end
;
Nous avons encore fait appel à la fonction Convert, mais cette fois avec des paramètres différents. Convert est en effet redéfini deux fois dans l'unité ConvUtils.
Voyons maintenant le deuxième mode de conversion…
I-C-2. La conversion procédurale▲
La conversion procédurale recherche un résultat qui n'est plus lié à un simple facteur de conversion, mais qui est pris en charge par une fonction de conversion implémentée par le développeur (exécution de méthodes d'un objet, récupération de données dans un SGBD, etc.).
Dans une application se chargeant d'effectuer une conversion francs/euros, nous aimerions que la routine de conversion se charge en plus d'appliquer l'arrondi bancaire.
Nous allons créer une application base de données locale de 1er niveau, utilisant un ClientDataSet qui servira de table locale pour stocker des enregistrements. Chaque enregistrement stockera un tarif en euros pour un article donné. Nous saisirons les montants en euros, mais pour un temps indéterminé nous souhaitons pouvoir afficher le montant respectif en francs. À cet effet, nous utiliserons un champ calculé pour l'affichage des montants en francs. De fait, lorsque nous n'aurons plus besoin de visualiser les prix en francs, il sera aisé de supprimer le champ calculé, sans pour autant modifier la structure de la table.
La conversion en elle-même est aussi simple que pour le premier exemple, puisque la conversion francs/euros ne tient qu'à une simple opération de multiplication ou de division réalisée par la fonction Convert (facteur multiplicateur de 6.55957).
Mais cela ne nous suffit pas, nous aimerions effectuer un arrondi bancaire sur le résultat, et surtout que le calcul de cet arrondi soit pris en charge par la routine de conversion elle-même.
L'unité EuroConv livrée dans les démos effectue cette opération en surchargeant certaines routines de ConvUtils de façon à personnaliser la conversion. En l'occurrence, après conversion classique d'une monnaie vers l'autre, le résultat est passé à la fonction SimpleRound qui effectue l'arrondi bancaire. On a bien ici une spécialisation de la conversion de base :
Result := AValue / Factor;
Revenons à notre application et dans la clause uses section implémentation de votre fiche, ajoutez une référence à l'unité EuroConv.
var
frmEuroFranc: TfrmEuroFranc;
implementation
uses
ConvUtils, EuroConv;
Attention l'unité EuroConv est située dans le dossier $DELPHI\Demos\ConvertIt, ce chemin doit être connu dans les options du projet (Répertoires/Chemin de Recherche) ou bien copiez-le dans le même dossier que votre application. L'unité EuroConv est un ajout de Borland au framework de conversion initial, en guise d'exemple de personnalisation. Elle recense toutes les monnaies liées à l'euro et permet donc de réaliser les conversions dans tous les sens de monnaie possibles.
I-C-2-a. Création de l'ensemble de données▲
Ensuite, disposez un TClientDataSet sur la fiche, double-cliquez dessus pour ouvrir l'éditeur de champs, ensuite un clic droit sur l'éditeur donne accès au menu [Nouveau Champ] (fig. 3).
Ajoutez les champs suivants :
Nom du champ |
Type de champ |
Type de donnée |
Valeur |
---|---|---|---|
IDTarif |
Données |
AutoInc |
|
LibelleTarif |
Données |
String |
100 |
TarifsEuro |
Données |
Float |
|
TarifsFrancs |
Calculé |
Float |
Ensuite, à l'aide du menu contextuel sur le ClientDataSet, sélectionnez [Créez un ensemble de données].
I-C-2-b. Connexions aux contrôles visuels▲
Disposez un DBGrid, un DBNavigator et des champs DB d'édition, tous reliés via un Datasource à l'ensemble de données client ci-dessus (fig. 4).
À l'ouverture de l'application, nous activerons le ClientDataSet et le désactiverons à la fermeture.
procedure
TfrmEuroFranc.FormCreate(Sender: TObject);
begin
cdsTarif.Active := True
;
end
;
procedure
TfrmEuroFranc.FormDestroy(Sender: TObject);
begin
cdsTarif.Active := False
;
end
;
I-C-2-c. Réalisation de la conversion▲
Puisque c'est un champ calculé qui affichera le montant en francs respectif au montant saisi en euros, nous implémenterons la conversion en gérant l'événement OnCalcField du ClientDataSet :
procedure
TfrmEuroFranc.cdsTarifCalcFields(DataSet: TDataSet);
begin
TarifFrancs.Value := Convert(TarifEuros.Value, euEUR, euFFR);
end
;
euEUR et euFFR sont des types d'unités de mesure déclarés dans l'unité EuroConv, et représentent respectivement les unités de mesure source et destination nécessaires à la conversion.
Avantage de l'opération : comme pour le premier exemple, un appel à la fonction Convert a suffi pour obtenir une conversion de données. Cependant cette dernière ici élargissait l'opération de base en ajoutant le calcul de l'arrondi bancaire.
On peut en conclure que nous bénéficions d'un ensemble cohérent et générique, quelle que soit la complexité de l'opération de conversion. Nous allons à présent étudier comment fonctionne ce framework de conversion et comment implémenter des conversions personnalisées non disponibles dans l'unité StdConvs et EuroConv.
Nous allons à présent découvrir le fonctionnement interne, à savoir comment les conversions sont réalisées par Delphi (et Kylix).