Site:  Cours VB.net  
  3.30

Programmation fonctionnelle: l'IMC.

Ce chapitre permet de 'réviser' pas mal de notion.

Qu'est ce que l'IMC?

L'index de masse corporelle est très utilisé par les médecins. Il est calculé à partir du poids et de la taille:

IMC=Poids/(Taille*Taille)  (avec Poids en Kg, Taille en mètres)

Cela permet de savoir si le sujet est

maigre (IMC<18.5)

normal (IMC idéale=22)

en surpoids (IMC>25)

obèse (IMC>30).

On peut calculer le poids idéal par exemple PI= 22* T*T

Nous allons détailler ce petit programme:

 

Quel est le cahier des charges du programme?

L'utilisateur doit pouvoir:

Saisir un poids, une taille, cliquer sur un bouton 'Calculer'

Les routines doivent:

Vérifier que l'utilisateur ne fait pas n'importe quoi.

Calculer et afficher les résultats: l'IMC mais aussi, en fonction de la taille, le poids idéal, les poids limites de maigreur, surpoids, obésité.

 

Création de l'interface

Il faut 2 zones de saisie pour saisir le poids et la taille:

On crée 2 'TextBox' que l'on nomme

TexBoxPoids 

TextBoxTaille.

On laisse la propriété Multiline à False  pour n'avoir qu'une ligne de saisie.

Pour afficher les résultats , on crée 5 'label' les uns sous les autres. (Pour aller plus vite et que les labels soient de la même taille, on en crée un puis par un copier et des coller, on crée les autres)

labelImc    'pour afficher l'Imc

labelPi     'pour afficher le poids idéal

labelM      'pour afficher le poids limite de la maigreur.

labelS      'pour afficher le poids limite du surpoids

labelO      'pour afficher le poids limite de l'obésité.

Ensuite  on ajoute des labels devant et derrière chaque TextBox  pour indiquer devant, ce qu'ils contiennent et derrière, l'unité.

On ajoute 2 boutons:

ButtonCalcul ayant pour propriété Text= "&Calculer"

ButtonQuitter ayant pour propriété Text= "&Quitter"

Cela donne:

Pour faire beau:

La propriété Text de la fenêtre contient "Calcul IMC", pour afficher cela dans la barre de titre.

La propriété ForeColor de labelImc est en rouge.

La propriété BorderStyle des labels a la valeur 'Fixed3d' ce qui rend les bords visibles.

Ajout du Code

La procédure évènement Form1_Load qui se déclenche lorsque la fenêtre se charge initialise les zones d'affichage en les vidant:

 

Private Sub Form1_Load(..)

TextBoxTaille.Text = ""

TextBoxPoids.Text = ""

LabelImc.Text = ""

LabelPi.Text = ""

LabelM.Text = ""

LabelS.Text = ""

LabelO.Text = ""

End Sub

 

La procédure ButtonCalcul_Click qui se déclenche lorsque l'utilisateur clique sur le bouton 'Calculer' contient le code principal.

 

Voici la totalité du code, on le détaillera dessous.

Private Sub ButtonCalcul_Click(..)

 

Dim sPoids As Single  'Variable Single contenant le poids

Dim sTaille As Single 'Variable Single contenant la taille

'******Controle de validité des entrées************

'Les valeurs saisies sont-elles numérique?

If Not (IsNumeric(TextBoxTaille.Text)) Then

    MsgBox("Entrez une valeur numérique pour la taille")

    Exit Sub

End If

If Not (IsNumeric(TextBoxPoids.Text)) Then

    MsgBox("Entrez une valeur numérique pour le poids")

    Exit Sub

End If

'Convertir les textes saisis en single

' et les mettre dans les variables

sTaille = CType(TextBoxTaille.Text, Single) / 100

sPoids = CType(TextBoxPoids.Text, Single)

'Les valeurs saisies sont-elles cohérentes?

If sTaille < 0.50 Or sTaille > 2.50 Then

    MsgBox("Entrez une taille valide")

    Exit Sub

End If

    If sPoids < 20 Or sPoids > 200 Then

    MsgBox("Entrez un poids valide")

Exit Sub

End If

'Effectuer les calculs et afficher les résultats.

LabelImc.Text = (Math.Round(sPoids / (sTaille * sTaille), 2)).ToString

LabelPi.Text = (Math.Round(22 * (sTaille * sTaille), 2)).ToString

LabelM.Text = (Math.Round(18.5 * (sTaille * sTaille), 2)).ToString

LabelS.Text = (Math.Round(25 * (sTaille * sTaille), 2)).ToString

LabelO.Text = (Math.Round(30 * (sTaille * sTaille), 2)).ToString

End Sub

 

Détaillons:

 

Quelles sont les différentes étapes?

On déclare les variables.

On vérifie que ce qui a été tapé est numérique.

On convertit le texte qui est dans la TextBox en Single

On teste si les valeurs de poids et taille sont cohérentes.

On fait le calcul et on affiche.

 

Déclaration de variables.

Dim sPoids As Single  'Variable Single contenant le poids

Dim sTaille As Single 'Variable Single contenant la taille

 Ce sont des variables 'privées' propre à la procédure (utilisation de Dim ou Private).

 

Contrôle de validité:

L'utilisateur est sensé taper un poids et une taille puis cliquer sur le bouton 'Calculer'. Mais il ne faut absolument pas lui faire confiance: il a peut-être oublié de taper le poids ou a donner une taille=0 (l'ordinateur n'aime pas diviser par 0!!), il a peut-être fait une faute de frappe et tapé du texte!!..

Donc il faut tester ce qui a été tapé, s'il y a erreur, on prévient l'utilisateur avec une 'MessageBox' puis on sort de la routine par (Exit Sub )sans effectuer de calcul.

 

Ici par exemple, on teste si le texte saisi dans la zone taille n'est pas numérique:

If Not (IsNumeric(TextBoxTaille.Text)) Then

    MsgBox("Entrez une valeur numérique pour la taille")

    Exit Sub

End If

 

Amélioration: On aurait pu automatiquement effacer la valeur erronée et placer le curseur dans la zone à ressaisir:

 

If Not (IsNumeric(TextBoxTaille.Text)) Then

    MsgBox("Entrez une valeur numérique pour la taille")

    TextBoxTaille.Text=""

    TextBoxTaille.Select()

    Exit Sub

End If


Conversion:

Si le texte est bien 'Numéric', on fait la conversion en réel simple précision (Single)

sTaille = CType(TextBoxTaille.Text, Single) / 100

On utilise CType pour convertir une String en Single.

On divise taille par 100 car l'utilisateur à saisi la taille en centimètre et les formules nécessitent une taille en mètre.

 

Problème du séparateur décimal dans les saisies.

Pourquoi saisir la taille en Cm? c'est pour éviter d'avoir à gérer le problème du séparateur décimal.

 

Si la taille était saisie en mètre, l'utilisateur aurait-il tapé "1.75" ou "1,75"?

On rappelle que pour convertir un texte en Single VB accepte le point et pas la virgule.

Pour ma part, si j'avais demandé de saisir des mètres, voici ma solution: j'ajouterais en début de routine une instruction transformant les ',' en '.':

TextBoxTaille.Text = Replace(TextBoxTaille.Text, ",", ".")

 

Faire les calculs et afficher les résultats.

 

Je fais le calcul:

sPoids / (sTaille * sTaille)

 

J'arrondis à 2 décimales après la virgule grâce à Math.Round(  ,2):

Math.Round(sPoids / (sTaille * sTaille), 2)

 

Je convertis en String:

(Math.Round(sPoids / (sTaille * sTaille), 2)).ToString

 

J'affiche dans le label 'labelImc':

LabelImc.Text = (Math.Round(sPoids / (sTaille * sTaille), 2)).ToString

 

(J'aurais pu aussi ne pas arrondir le calcul mais formater l'affichage pour que 2 décimales soient affichées)

 

 

La procédure ButtonQuitter_Click déclenchée quand l'utilisateur clique sur le bouton 'Quitter' ferme la seule fenêtre du projet (c'est Me , celle où on se trouve), ce qui arrête le programme.

Private Sub ButtonQuitter_Click()

    Me.Close()

End Sub

 

 

Structuration:

Ici on a fait simple: une procédure évènement calcule et affiche les résultats.

On pourrait, dans un but didactique 'structurer' le programme.

 

 

On pourrait découper le programme en procédure.

    Une procédure (une fonction) faisant le calcul.

    Une procédure (une fonction) affichant les résultats.

 

Si plusieurs procédures utilisent les mêmes variables il y a dans ce cas 2 possibilités:

    Mettre les variables en 'Public' dans un module Standard.

    Utiliser des variables privées et les passer en paramètres.

 

Première solution: Variables 'Public'

Créer dans un module standard des variables 'Public' pour stocker les variables Poids et Taille, résultats (Public sIMC A Single par exemple),créer dans ce même module standard une procédure Public nommée 'Calculer' qui fait les calculs et met les résultats dans les variables 'Public'; enfin dans le module de formulaire créer une procédure 'AfficheResultat' affichant les résultats.

 

Module standard:

'Déclaration de variables Public

Public sPoids As Single

Public sTaille As Single

Public sIMC A Single

..

'Procedure Public de calcul

Public Sub Calculer

    sIMC=Math.Round(sPoids / (sTaille * sTaille), 2)

    ...

End Sub

 

Module de formulaire Form1:

'Procédure évènement qui appelle les divers routines

Private Sub ButtonCalculer_Click

    ...

    sTaille = CType(TextBoxTaille.Text, Single) / 100

    Calculer()    'Appelle la routine de calcul

    AfficheResultat() 'Appelle la routine d'affichage

End Sub

 

'routine d'affichage toujours dans le formulaire

Private Sub AfficheResultat()

   

    LabelImc.Text = sIMC.ToString

    ...

End Sub

 

On voit bien que la routine de Calcul est générale et donc mise dans un module standard et d'accès 'Public', alors que la routine d'affichage affichant sur Form1 est privée et dans le module du formulaire.

 

Seconde solution: Variables 'Privées' et passage de paramètres

 

On peut ne pas créer de variables 'public' mais créer des fonctions (CalculIMC par exemple) à qui on passe en paramètre le poids et la taille et qui retourne le résultat du calcul. Une procédure AfficheResultatIMC récupère en paramètre la valeur de l'IMC à afficher.

 

Module standard:

'Pas de déclaration de variables Public

..

'Function Public de calcul: reçoit en paramètre le poids et la taille

'retourne l'Imc

Public Function CalculerIMC (T as Single, P As Single) As Single

    Return Math.Round(P / (T*T), 2)

End Sub

 

Module de formulaire Form1:

'Procédure évènement qui appelle les divers routines

Private Sub ButtonCalculer_Click

    ...

    sTaille = CType(TextBoxTaille.Text, Single) / 100

   

    'Appelle de la routine calcul avec l'envoie de paramètres sPoids et sTaille

    'Au retour on a la valeur de L'imc que l'on envoie à la routine d'affichage.

    AfficheResultatIMC(CalculerIMC(sTaille, sPoids)) 'Appelle la routine d'affichage

End Sub

 

'routine d'affichage

Private Sub AfficheResultatIMC(I As Single)

    LabelImc.Text = i.ToString

End Sub

 

Remarque:

La ligne AfficheResultatIMC(CalculerIMC(sTaille, sPoids))

est équivalente à:

Dim s As single

s=(CalculerIMC(sTaille, sPoids)

AfficheResultatIMC(s))

mais on se passe d'une variable temporaire.

 

Conclusion:

Faut-il travailler avec des variables Public ou passer des paramètres?

Réponses:

Les savants disent qu'il faut éviter les variables Publics. Toutes les routines ayant accès à ces variables, il est toujours possible qu'une routine modifie une valeur sans qu'on le sache!!

 

  Utiliser donc des variables le plus privées possible. 

(on y reviendra)