Convertisseur Francs / Euros

 

Version : 0.1.2 Date :08 février 2002


TkFEF : un convertisseur Francs/Euros par David Cobac


Comme c'est original par les temps qui courent !!



TkFEF : commentaires du code ligne par ligne



Objectif


L'objectif est de créer un convertisseur francs/euros dans les deux sens. Il doit fonctionner à l'instar de ce qu'on peut voir dans les magasins : la frappe sur une touche actualise illico la conversion.


Aspect graphique


L'interface se doit d'être simplissime : deux entrées une pour les francs et une autre pour les euros ; ces deux entrées seront "complétées" par deux étiquettes indiquant la monnaie associée. Voilà à quoi nous devons aboutir : illustration


Codons !


l'interface graphique

les widgets

Les deux entrées serons nommées simplement : .e0 et .e1 les deux étiquettes : .l0 et .l1 Les widgets (objets graphiques) associés sont entry pour les entrées et label pour les étiquettes, ce qui nous donne :

 entry .e0 -width 10
 label .l0 -text "Francs"
 entry .e1 -width 10
 label .l1 -text "Euros"

On a associé à l'entrée .e0 l'étiquette .l0 et à l'entrée .e1 l'étiquette .l1 (remarquons que ce choix est tout à fait libre et n'est fait que pour rendre l'identification des widgets faciles pour le programmeur). On a choisi une largeur de 10 caractères pour les entrées et le texte des étiquettes a été fixé dans la définition même de celles-ci.

le placement

Nous venons de définir nos widgets mais pas de les afficher ! Pour ce faire, on peut utiliser 3 méthodes : pack, grid et place. La méthode place permet de placer les widgets sur une fenêtre graphique de manière précise au pixel près et donc semble peu adapter à notre situation où nous ne connaissons pas grand chose de nos widgets. La méthode pack permet de réaliser facilement des interfaces complexes. Très utilisée, elle pourrait convenir à un détail près : nous voudrions avoir exactement les deux entrées l'une en dessous de l'autre et les deux étiquettes de la même manière, tous comme une grille à 4 éléments. C'est donc la méthode grid que nous utiliserons, elle permet de placer dans une grille les widgets que vous voulez, il suffit juste de préciser où ils doivent se situer : par exemple grid pourra mettre une entrée à la ligne 3 colonne 2 et une étiquette à la ligne 1 colonne 1 etc. Ainsi nous coderons :

 grid .e0 -row  1 -column 1
 grid .l0 -row 1 -column 2
 grid .e1 -row  2 -column 1
 grid .l1 -row 2 -column 2

En anglais row signifie ligne (de grille) et column signifie colonne.

Pour raccourcir notre code, nous définirons et placerons dans la grille simultanément :

 grid [entry .e0 -width 10] -row  1 -column 1
 grid [label .l0 -text "Francs"] -row 1 -column 2
 grid [entry .e1 -width 10] -row  2 -column 1
 grid [label .l1 -text "Euros"] -row 2 -column 2

la procédure de conversion

des petits rappels

Toute commande passée entre crochets sera évaluée et renverra son résultat. La commande catch permet d'intercepter les erreurs.

convertissons

La question importante est : notre procédure a-t-elle besoin d'arguments ? La réponse est immédiate : si notre procédure doit pouvoir faire la conversion dans les deux sens, il faut lui dire dans quel sens nous souhaitons la faire. Nous allons donc passer à notre procédure l'argument operation qui vaudra * pour faire la multiplication à 6.55957 (euros->francs) et qui vaudra / pour faire l'autre conversion. Voilà donc un premier jet :

 proc conversion {operation} {
     set somme [.e0 get]
     .e1 delete 0 end
     .e1 insert 0 [expr $somme $operation 6.55957]
 }

ligne 1 : définition de ma procédure

ligne 2 : on prend ce qu'il y a dans l'entrée .e0 et on l'attribue à la variable somme

ligne 3 : on efface ce qu'il y a (on sait jamais) dans l'entrée .e1 du début (0) à la fin (end)

ligne 4 : on met au début (0) dans l'entrée .e1 le résultat de notre conversion

Ce script paraît idéal à un détail près : l'entrée .e0 doit normalement toujours correspondre aux francs ce qui n'est pas le cas ici puisque c'est toujours dans .e0 que nous allons chercher la somme à convertir... Une alternative s'offre à nous : soit nous testons la valeur de l'opération passée en arguments à l'aide d'un test soit nous passons deux arguments supplémentaires à notre procédure : les deux entrées C'est cette deuxième solution que j'ai retenue. Ce qui imposera d'appeler la conversion francs->euros par :

 conversion .e0 .e1 *

et l'autre par :

 conversion .e1 .e0 /

Le code devient donc :

 proc conversion {entree0 entree1 operation} {
     set somme [$entree0 get]
     $entree1 delete 0 end
     $entree1 insert 0 [expr $somme $operation 6.55957]
 }

raffinements nécessaires

Notre code n'est pas tout à fait satisfaisant : si je mets dans une entrée une lettre au lieu d'un chiffre, le script plantera il faudrait donner le résultat avec deux chiffres après la virgule, c'est-à-dire formater le résultat de notre calcul

Le premier problème sera vite résolu grâce à la commande catch qui va se contenter d'intercepter l'erreur donc en cas d'erreur, votre entrée sera simplement ignorée.

Le deuxième problème sera résolu grâce à la commande format qui permet de mettre en forme un nombre donné avec le format d'affichage voulu.

Bref, notre code final de conversion est :

 proc conversion {entree0 entree1 operation} {
     set somme [$entree0 get]
     $entree1 delete 0 end
     catch {
         $entree1 insert 0 [format "%.2f" [expr $somme $operation 6.55957]]
     } erreur
 }

lien entre l'interface et la conversion

Je rappelle que nous n'appuyons sur aucun bouton pour convertir la somme rentrée mais que la conversion s'effectue juste après appui sur une touche dans une des entrées.

Nous avons tout dit !!

La commande bind permet d'associer à chaque évenement sur un widget une commande. Il nous faut définir deux actions : on vient de rentrer quelque chose dans l'entrée .e0 il faut donc le multiplier par 6.55957 et mettre le résultat dans l'entrée .e1 on vient de rentrer quelque chose dans l'entrée .e1 il faut donc le diviser par 6.55957 et mettre le résultat dans l'entrée .e0 Tout ceci se traduit en Tcl par :

 bind .e0 <KeyRelease> "conversion .e0 .e1 /"
 bind .e1 <KeyRelease> "conversion .e1 .e0 *"

Notons que l'évenement n'est pas KeyPress mais bien KeyRelease puisque KeyPress intervient avant que l'entrée ne soit remplie par l'appui sur la touche.


Code final


Pour finir, on a simplement réunit tout ce qui concerne les widgets dans une procédure nommée gui (pour Graphical User Interface), puis simplement appelé cette procédure.

 proc conversion {entree0 entree1 operation} {
     set somme [$entree0 get]
     $entree1 delete 0 end
     catch {
         $entree1 insert 0 [format "%.2f" [expr $somme $operation 6.55957]]
     } erreur
 }
 proc gui {} {
     grid [entry .e0 -width 10] -row  1 -column 1
     grid [label .l0 -text "Francs"] -row 1 -column 2
     grid [entry .e1 -width 10] -row  2 -column 1
     grid [label .l1 -text "Euros"] -row 2 -column 2
     bind .e0 <KeyRelease> "conversion .e0  .e1 /"
     bind .e1 <KeyRelease> "conversion .e1 .e0 *"
 }
 gui