Approche d'une résolution de besoin en VBA niveau débutant Obliger une saisie numérique dans une TextBox

Didier Gonard

L'objectif de ce tutoriel n'est pas, seulement, de présenter une solution, là où un article dans la FAQ pourrait suffire, mais d'en détailler la construction en partant du besoin pour arriver au code final en explicitant les choix adoptés.

Commentez

- Titre : Approche d'une résolution de besoin en VBA niveau débutant Obliger une saisie numérique dans une TextBox

- Auteur : Didier Gonard

- Parution : 9 mars 2010

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ®  Didier Gonard. 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. Droits de diffusion permanents accordés à Developpez LLC.

Sommaire

- I. Préambule

- II. Introduction

- III. En premier lieu

- IV. Exposer la problématique

- V. Attaquer la construction de notre exemple

- V-A. N'accepter que des chiffres, une virgule ou un signe -

- V-B. N'accepter qu'un seul signe moins, situé en début de chaîne.

- V-C. N'accepter qu'une seule virgule positionnable à l'endroit voulu.

- V-D. Interdire le point en saisie

- V-E. Ne pas laisser un copier coller permettre une saisie non conforme

- V-E-1. Que la chaîne ne soit pas vide

- V-E-2. Qu'elle ne comporte pas de points

- V-E-3. Que si elle ne comporte qu'un seul caractère et que celui-ci ne fait pas partie d'un des 10 chiffres, on la refuse

- V-E-4. Qu'elle soit bien une chaîne qui représente un nombre tel que défini au départ.

- V-F. Écrire la valeur de notre textbox dans la feuille

- V-F-1. Notre code final

- V-G. Pourquoi ne pas employer la fonction IsNumeric ou l'opérateur Like

- V-G-1. Fonction IsNumeric

- V-G-2. Opérateur Like

- V-G-3. Il en résulte que

- VI. Liens utiles

- VII. Remerciements

- VIII. Téléchargement

I - Préambule

Dans ce tutoriel, nous conviendrons des choses suivantes :

- Les définitions en italique des mots clefs VBA sont les définitions édulcorées issues de l'aide VBA adaptées à notre contexte. N'hésitez pas à consulter l'aide pour plus de détails.

- Le lecteur voulant piloter une TexBox dans un Userform est censé savoir constuire un Userofrm basic et y inclure une textbox.

II - Introduction

Mon ami, Benoît Chiffrentext, profitant d'un passage chez moi m'a demandé si je pouvais l'aider à résoudre le problème suivant : il voulait pouvoir, dans un Userform de sa fabrication, n'accepter qu'une saisie numérique au niveau d'une TextBox. Il avait bien compris que ce contrôle, bien nommé, ne renvoyait que des Strings, mais il n'arrivait pas à obtenir un code le satisfaisant devant les contraintes suivantes :

- Il voulait, par l'emploi de boîtes de saisie, moderniser et fiabiliser son application pour une association, dont les bénévoles disposaient de portables, pour la plupart sans pavé numérique, et avaient l'habitude de saisir les chiffres avec la touche shift et une virgule directement dans les cases.

- Il avait constaté que la saisie à l'aide d'un pavé numérique ne posait pas de soucis, les points étant convertis de façon magique lors de l'écriture dans une cellule.

- Il a déchanté quand il s'est aperçu que si les personnes saisissaient dans sa TextBox un nombre à virgule, il apparaissait comme un texte dans les cellules.

- Il a désespéré en tentant d'imposer le point en saisie car :

1. Les utilisateurs par habitude commettaient énormément d'erreurs.

2. Ceux qui y arrivaient, du coup, en saisie feuille normale entraient un nombre avec un point clavier directement dans une cellule et se retrouvaient avec une donnée texte (alors que la même saisie sur un pavé numérique ne pose aucun problème)*.

Nous avons donc posé le problème et trouvé une solution qui lui convenait.

* Si dans une cellule on tape 12 "point" 5 avec le pavé numérique, on obtient 12,5 alors que si on tape 12 "point" 5 avec le clavier on obtient 12.5 . Les deux "point" sont interprétés différemment (suivant les options régionales). Par contre en VBA si on veut 12,5 en A1, il faudra entrer en code :

range ("A1") = 12.5

III - En premier lieu

Si on veut gagner du temps, il faut accepter d'en… perdre ai-je expliqué à mon ami Benoît Chiffrentext. En effet pour aller vite, il s'était rué sur son éditeur VBA et il tournait en rond avec diverses solutions non satisfaisantes.
Je lui ai alors demandé d'estimer le temps déjà passé et suggéré une autre approche, moins rapide à première vue, mais qui aurait, au final, tous les atouts en terme de temps passé, d'atteinte du but recherché, de portabilité et de maintenance.
Nous avons donc pris une feuille de papier (ce n'est pas un virtuose de la frappe) et avons listé les éléments du chapitre suivant.

IV - Exposer la problématique

Nous voulons en premier lieu :

- Entrer, dans une TextBox, des nombres positifs ou négatifs qui alimenteront certaines cases d'une feuille, dans le format voulu, après la validation globale de l'USF.

- Pouvoir corriger la frappe en cours de route.

- Accepter les nombres à virgule.

- N'accepter que les nombres en base 10 et en représentation simple.

- Refuser toute entrée qui ne correspondrait pas à un nombre selon nos normes.

- Assurer le meilleur confort de saisie pour l'utilisateur, ce qui est en fait notre priorité une fois les contraintes techniques respectées.

Quelles solutions pouvons-nous adopter :

1. Contrôler la validité de la saisie au moment où la TextBox est quittée ou l'USF validé.

2. Contrôler directement la saisie lors de la frappe dans la TextBox.

Les différentes tentatives de mon ami Benoît Chiffrentext, avoir une interface professionnelle et surtout le confort de l'utilisateur nous font pencher pour la deuxième solution.

Quels sont les buts à atteindre ? Nous voulons en saisie :

1. N'accepter que des chiffres, une virgule ou un signe - (donc pas blancs).

2. N'accepter qu'un seul signe moins et situé en début de chaîne.

3. N'accepter qu'une seule virgule positionnable à l'endroit voulu.

4. Interdire le point en saisie.

Avons-nous pensé à tout ? L'utilisateur peut-il opérer une manipulation non prévue demandais-je à mon ami ?
Oui, nous avons tout verrouillé, me répondit-il... Euh ! sauf le copier-coller peut-être ?
En effet si l'utilisateur fait un copier dans la TextBox directement, notre système de contrôle à la frappe ne vas pas réagir, on va donc ajouter la ligne E à notre liste.
Puis la ligne F pour noter ce qui est quand même notre but final : écrire la valeur voulue dans une case d'une feuille en format nombre.

La liste devient donc :

1. N'accepter que des chiffres, une virgule ou un signe - (donc pas de blancs).

2. N'accepter qu'un seul signe moins et situé en début de chaîne.

3. N'accepter qu'une seule virgule positionnable à l'endroit voulu.

4. Interdire le point en saisie.

5. Ne pas laisser un copier coller permettre d'effectuer une saisie non conforme.

6. Écrire la valeur de notre TextBox dans une case en format nombre.

En dernier lieu, une question non négligeable : notre code est-il destiné à un usage unique ou rare ou risque-ton d'y faire appel de façon récurrente ?
Si oui, peut-on le construire sous forme de fonction ?

V - Attaquer la construction de notre exemple

On commence par construire un USF nommé : "usfSaisieNumerique" dans lequel on place une TextBox nommée : "txtEcritFeuille" et un CommandButton nommé : "cmdAlimLesCasesFeuille". Un clic sur ce dernier validera l'affectation de la valeur de notre TextBox dans la case voulue de notre feuille.
Nous allons détailler pas à pas la démarche constructive du code en reprenant la notation de A à F de nos buts à atteindre : la démarche est hiérarchique et nous n'expliciterons au fur et à mesure que les mots clefs non explicités auparavant.

Cet Userform est non modal par construction, il vous permet d'intervenir sur les cases non protégées de la feuille.

V-A - N'accepter que des chiffres, une virgule ou un signe -

Nous allons pour ça utiliser une Instruction IF Then Else classique sous la forme :

Private Sub txtEcritFeuille_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If InStr("1234567890,-", Chr(KeyAscii)) = 0 Then KeyAscii = 0
End sub

Décomposons cette ligne : If InStr(''0123456789'',-, Chr (KeyAscii)) = 0 Then KeyAscii = 0

1. La fonction Chr renvoie une valeur de type String contenant le caractère associé au code de caractère indiqué de la variable Keyascii qui correspond au code de la touche pressée dans notre procédure.

2. InStr(string1, string2), la fonction InStr renvoie une valeur de type Variant, indiquant la position de la première occurrence d'une chaîne( string2) à l'intérieur d'une autre chaîne (string1). Ici nous avons : String1 ="1234567890,-" et string2 = Chr (KeyAscii)).

3. Fonction = 0 : Instr n'a pas trouvé d'occurrence dans notre chaîne de référence et retourne donc la valeur 0.

4. Then KeyAscii = 0 : on attribue une valeur nulle à la touche pressée ce qui équivaut à annuler l'appui de cette touche.

Traduction: Si on ne trouve pas d'occurrence au caractère correspondant à la touche pressée, dans notre chaîne de référence, alors on ne tient pas compte de l'appui sur cette touche.

Nous testons ceci dans notre Userform, et mon ami Benoît remarque fort justement, que nous obtenons l'effet voulu, mais que l'utilisateur va avoir la sensation que c'est son clavier qui bloque. Ne pourrait-on pas mettre un message d'erreur ?
Pourquoi pas, mais lourd à supporter par l'utilisateur dans cette configuration ; on décide donc plutôt de mettre un "Beep" et on notifiera dans le corps du Userform qu'il indique une saisie interdite (on sait que les utilisateurs lisent rarement les notices).

Notre code devient :

Private Sub txtEcritFeuille_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If InStr("1234567890,-", Chr(KeyAscii)) = 0 Then KeyAscii = 0 : Beep
End sub

V-B - N'accepter qu'un seul signe moins, situé en début de chaîne.

Nous voulons refuser un signe -, accepté en premier lieu par notre filtre 1, qui ne serait pas placé en début de chaîne : nous allons pour ça compléter notre filtre :

en rajoutant un Opérateur Or sous la forme :

Private Sub txtEcritFeuille_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If InStr("1234567890,-", Chr(KeyAscii)) = 0 Or txtEcritFeuille.SelStart > 0 And Chr(KeyAscii) = "-"  _
Then KeyAscii = 0: Beep
End If

Décomposons cette partie : Or txtEcritFeuille.SelStart > 0 And Chr(KeyAscii) = ''-''

1. La propriété Selstart indique le début du texte sélectionné, ou le point d'insertion. S'il n'y a pas de texte sélectionné, la plage des valeurs valides est comprise entre 0 et le nombre total des caractères dans la zone d'édition d'un contrôle ComboBox et va donc nous retourner la position qui sera occupée par le caractère pressé ; si celle-ci ne correspond pas à la première (0), on annule la saisie.

2. And Chr(KeyAscii) = "-" s'assure que Selstart ne s'applique qu'au caractère voulu.

Traduction: Ou bien, si le point d'insertion du caractère n'est pas en première position (et) alors qu'il s'agit du signe -, alors on ne tient pas compte de l'appui sur cette touche.

V-C - N'accepter qu'une seule virgule positionnable à l'endroit voulu.

A ce stade, nous voulons permettre la frappe d'une virgule n'importe où entre deux chiffres, mais d'une seule. Nous allons pour cela compléter notre filtre :

en y rajoutant un nouvel opérateur Or sous la forme :

Private Sub txtEcritFeuille_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If InStr("1234567890,-", Chr(KeyAscii)) = 0 Or txtEcritFeuille.SelStart > 0 And Chr(KeyAscii) = "-" _
Or InStr(txtEcritFeuille.Value, ",") <> 0 And Chr(KeyAscii) = ","  Then KeyAscii = 0: Beep
End If

Décomposons cette partie : Or InStr(txtEcritFeuille.Value, ",") <> 0 And Chr(KeyAscii) = ","

1. On emploie, à nouveau, InStr pour tester s'il y a déjà une virgule existante dans la chaîne.

2. Et on teste si le caractère frappé est aussi une virgule (qui serait donc alors en trop), nous la refusons si c'est le cas.

Traduction : Ou bien, s'il existe une virgule déjà présente dans la chaîne, et que le caractère frappé est une virgule : c'est à dire qu'on tente d'en saisir une deuxième, elle est refusée.

V-D - Interdire le point en saisie

Là le travail est déjà fait car le point ne fait pas partie de notre chaîne de référence.

V-E - Ne pas laisser un copier coller permettre une saisie non conforme

La première idée à ce stade serait de chercher à interdire le copier-coller, notamment en contrôlant le presse papier. Mais cette solution est plus ardue qu'il n'y paraît sachant qu'on ne peut se contenter de ne considérer que le presse papier premier niveau d'Excel, il faut aussi tenir compte de celui de Windows, ce qui sort du cadre de ce tutoriel.
Sachant qu'il n'y a aucun évènement direct Paste au niveau de la TextBox, on va donc de nouveau lister les différents points qu'il nous faut résoudre à ce niveau  :

1. Que la chaîne ne soit pas vide.

2. Qu'elle ne comporte pas de points.

3. Que si elle ne comporte qu'un seul caractère et que celui-ci ne fait pas partie d'un des 10 chiffres, on la refuse.

4. Qu'elle soit bien une chaîne qui représente un nombre tel que défini au départ.

On va donc se servir de l'évènementiel suivant pour contrôler la valeur de notre textbox avant qu'elle ne soit validée :
Private Sub txtEcritFeuille_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) ; qui survient avant la modification des données dans un contrôle.

On va devoir donc, écrire un code qui revient à vérifier de façon globale une saisie quand elle est complète. Ce qu'on aurait pu se contenter de faire donc et d'économiser notre code précédent si nous n'avions voulu assurer une ergonomie professionnelle à notre future application.
En introduction, nous nous étions posé la question suivante :
"En dernier lieu, une question non négligeable, notre code est-il destiné à un usage unique ou rare ou risque-ton d'y faire appel de façon récurrente ? Si oui, peut-on le construire sous forme de fonction ?"
La réponse est oui. Nous allons donc en profiter pour construire une fonction à ce niveau à titre d'exemple avec le code suivant :

Private Sub txtEcritFeuille_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
Dim strpass As String
strpass = txtEcritFeuille.Value
If ChainePasOK(strpass) = True Then Cancel = True: txtEcritFeuille.Value = "": Beep: MsgBox _
"Saisie non valide !"
End Sub

Notre fonction va donc s'appeler "ChainePasOK" et sera destinée à retourner une valeur booléenne (true ou false) qui nous dira si la chaîne proposée doit être rejetée ou non.
Pour lui passer la chaîne à étudier, nous allons nous servir de la variable strpass à qui on attribue la valeur de notre TextBox .
Notre fonction "ChainePasOK" qui par défaut est à False, passera à True si on rejette la chaîne.

If ChainePasOK(strpass) = True Then Cancel = True: txtEcritFeuille.Value = "": Beep: MsgBox "Saisie non valide !"

Traduction: Si la valeur renvoyée est à True, alors on affecte True au paramètre Cancel de la macro, puis une chaîne vide à la TextBox, on émet un Bip et on affiche un message : "Saisie non valide !"

Nous allons, de nouveau, détailler pas à pas la démarche constructive du code en reprenant la numérotation de nos buts à atteindre dans notre fonction : la démarche est toujours hiérarchique et nous n'expliciterons au fur et à mesure que les mots clefs non explicités auparavant.

V-E-1 - Que la chaîne ne soit pas vide

Il est, en effet, inutile de lancer un traitement s'il s'agit d'une chaîne vide. Nous allons pour cela utiliser de nouveau une Instruction IF Then Else auto-explicite  :

If strpass = "" Then Exit Function

V-E-2 - Qu'elle ne comporte pas de points

Encore une instruction If Then Else sous la forme :

If Len(Replace(strpass, ".", "")) <> Len(strpass) Then ChainePasOK = True: Exit Function

Il n'y a que la fonction Len que nous ne connaissons pas encore, Len renvoie une valeur de type Long contenant le nombre de caractères d'une chaîne.

Traduction: Si la longueur de la chaîne obtenue en remplaçant un point par "rien" est différente de la longueur de la chaîne de base, c'est que notre chaîne comporte un point et on affecte donc True comme valeur au renvoi de notre fonction et on sort. La chaîne sera rejetée.

V-E-3 - Que si elle ne comporte qu'un seul caractère et que celui-ci ne fait pas partie d'un des 10 chiffres, on la refuse

If Len(strpass) = 1 And InStr("1234567890", strpass) = 0 Then ChainePasOK = True: Exit Function

Nous sommes là en pays connu maintenant.

Traduction: Si la longueur de la chaîne = 1 et qu'on ne trouve aucune occurrence de celle-ci dans les 10 chiffres ; alors on affecte True comme valeur au renvoi de notre fonction et on sort. La chaîne sera rejetée.

On exclut aussi, par la même occasion, une virgule ou un signe - seul

V-E-4 - Qu'elle soit bien une chaîne qui représente un nombre tel que défini au départ.

Une fois nos premiers filtres passés, reste à nous assurer que notre chaîne correspond bien à un nombre selon nos désirs (chiffres de 0 à 9, une virgule possible, positif ou négatif).
Pour cela, il serait pratique d'utiliser la fonction Val qui renvoie le nombre contenu dans une chaîne de caractère sous la forme d'une valeur numérique d'un type approprié et qui s'il n'y a pas de nombre trouvé renvoie 0 et non pas un message d'erreur. Par contre : les virgules ne sont pas reconnues, effectivement l'éditeur VBA ne reconnaît que le point en séparateur numérique.
Nous allons donc traiter la chaîne à tester en remplaçant (juste pour le test) la virgule, potentiellement existante, par un point ce qui nous permettra d'utiliser Val sans souci avec le code suivant :

strpass = Replace(strpass, ",", ".")

A ce niveau, nous allons mettre à profit cette autre particularité de la fonction Val : la fonction Val arrête la lecture de la chaîne au premier caractère ne faisant apparemment pas partie d'un nombre.
C'est ceci qui nous intéresse au plus haut point, en effet si nous avons affaire à une chaîne hétérogène qui comporte des lettres au milieu de chiffres, la lecture de la fonction VAL s'arrêtera au premier caractère non conforme rencontré. Nous pourrons alors mettre à profit, comme plus haut, l'astuce qui consiste à comparer la longueur de la chaîne ainsi obtenue avec l'original et constater, forcément, une différence dans ce cas précis.
Par contre, la fonction Len ne traite que les chaînes de caractères, hors nous venons, par l'emploi de Val d'en transformer une en expression numérique, nous allons donc nous servir, ensuite, de la fonction CStr qui convertit une expression numérique en chaîne de caractères pour retomber sur nos pieds.

Ce que nous faisons avec le code suivant :

If Len(CStr(Val(strpass))) <> Len(strpass) Then ChainePasOK = True

Traduction : Si la longueur de la chaîne composée des premiers caractères numériques rencontrés, avant un caractère autre, dans la chaîne à tester est différente de la longueur de cette dernière, c'est qu'il y a un caractère non voulu, on affecte donc True comme valeur au renvoi de notre fonction et on sort. La chaîne sera rejetée.

Le fait qu'un utilisateur puisse opérer à tout moment un copier-coller en cours de saisie rend inutile, toute idée de court-circuiter notre fonction qui fait double emploi au final lors d'une saisie clavier pure.

V-F - Écrire la valeur de notre textbox dans la feuille

Il ne nous reste plus qu'à inscrire la valeur récupérée dans la case voulue de notre feuille. C'est un des points qui posait d'ailleurs problème à mon ami Benoît, nous allons donc à ce niveau, à des fins pédagogiques, procéder volontairement à deux écritures, dont une seule sera celle recherchée.

"dont une seule sera celle recherchée", nous n'employons pas "dont une seule sera correcte", car il faut bien comprendre que c'est une question de contexte, les deux écritures sont informatiquement correctes, si le résultat, lui, n'est pas celui attendu, c'est notre façon de coder qu'il faut remettre en cause et non des comportements erratiques de l'instruction employée. Le résultat voulu pourrait d'ailleurs fort bien être un nombre sous forme de chaîne de caractère pour une autre interface.

Pour ceci, nous allons employer le code suivant :

Private Sub cmdAlimLesCasesFeuille_Click()
Cells(5, 1) = txtEcritFeuille.Value
End Sub

Nous obtenons ceci au niveau de notre feuille :

L'alignement par défaut à gauche de notre valeur dans la case A5 et le petit coin vert nous indiquent que la donnée écrite est considérée comme une chaîne de caractère, comme nous le confirme l'activation du pop-up :

Attention, ce comportement est à l'origine de beaucoup d'incompréhensions, car si on inclut cette cellule dans un calcul du genre "=A5+A7" avec un nombre en A7, nous aurons un bon résultat alors que si on passe par la fonction somme "=SOMME(A5;A7)", A5 ne sera pas prise en compte, ce qui, encore une fois, est normal et découle des règles d'interprétation d'Excel.

Nous l'avons vu, une TextBox, ne retourne que des valeurs de chaînes, c'est donc à nous de convertir notre valeur dans le format voulu afin de l'écrire selon nos désirs dans la case ciblée.

Nous allons employer pour cela le code suivant :

Private Sub cmdAlimLesCasesFeuille_Click()
Cells(5, 3) = CDbl(txtEcritFeuille.Value)
End Sub

La fonction CDbl convertit une expression (qui peut être n'importe quelle expression de chaîne ou expression numérique) en une variable de type Double (-1.79769313486231E308 à -4,94065645841247E-324 pour les valeurs négatives ; 4,94065645841247E-324 à 1,79769313486232E308 pour les valeurs positives).
Nous écrivons du coup notre valeur dans une cellule proche (C5 en vert) afin de bien visualiser le résultat.

Le résultat est bien, ici, celui recherché. Nous allons compléter notre code comme prévu afin de réaliser les deux types d'écritures et bien en visualiser le résultat.

Private Sub cmdAlimLesCasesFeuille_Click()

MsgBox "Cette donnée est de type :  " & TypeName(txtEcritFeuille.Value) & vbCr & vbLf _
& "Nous aurons donc du texte dans la case A5 alignée à gauche par défaut donc."
Worksheets("FeuilleCible").Cells(5, 1) = txtEcritFeuille.Value

Worksheets("FeuilleCible").Cells(5, 3) = CDbl(txtEcritFeuille.Value)
MsgBox "Cette donnée est de type :  " & TypeName(CDbl(txtEcritFeuille.Value)) & vbCr & vbLf _
& "Nous autrons donc un nombre à virgule flottante  dans la case C5 alignée à droite par défaut  "
End Sub

Le fait, ici, d'avoir des colonnes A et C élargies, fait ressortir les différences d'alignement dues au format, c'est nettement moins visible (et plus trompeur) dans des colonnes basiques suivant le nombre de chiffres !

Nous avons employé, ici, pour notre message d'information la fonction TypeName qui renvoie une valeur de type String correspondant au Type d'une variable.

V-F-1 - Notre code final

Le classeur avec cet UserForm (USF) est disponible en téléchargement (voir à la fin du tutoriel) .

Ne concerne que le code de l'Userfom

Option Explicit
Private Sub cmdAlimLesCasesFeuille_Click()
MsgBox "Cette donnée est de type :  " & TypeName(txtEcritFeuille.Value) & vbCr & vbLf _
& "Nous aurons donc du texte dans la case A5 alignée à gauche par défaut."
Worksheets("FeuilleCible").Cells(5, 1) = txtEcritFeuille.Value
'Effacer les lignes ci-dessus (sauf Privat...) pour appli finale
Worksheets("FeuilleCible").Cells(5, 3) = CDbl(txtEcritFeuille.Value)
'Effacer la ligne suivante pour appli finale
MsgBox "Cette donnée est de type :  " & TypeName(CDbl(txtEcritFeuille.Value)) & vbCr & vbLf _
& "Nous autrons donc un nombre à virgule flottante  dans la case C5 alignée à droite par défaut. "
End Sub
Private Sub txtEcritFeuille_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
Dim strpass As String
strpass = txtEcritFeuille.Value
If ChainePasOK(strpass) = True Then Cancel = True: txtEcritFeuille.Value = "": Beep: MsgBox "Saisie non valide !"
End Sub
Private Function ChainePasOK(strpass As String) As Boolean
If strpass = "" Then Exit Function
If Len(Replace(strpass, ".", "")) <> Len(strpass) Then ChainePasOK = True: Exit Function
If Len(strpass) = 1 And InStr("1234567890", strpass) = 0 Then ChainePasOK = True: Exit Function
strpass = Replace(strpass, ",", ".")
If Len(CStr(Val(strpass))) <> Len(strpass) Then ChainePasOK = True
End Function

Private Sub txtEcritFeuille_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If InStr("1234567890,-", Chr(KeyAscii)) = 0 Or txtEcritFeuille.SelStart > 0 And Chr(KeyAscii) = "-" _
Or InStr(txtEcritFeuille.Value, ",") <> 0 And Chr(KeyAscii) = "," Then
KeyAscii = 0: Beep
End If
End Sub

V-G - Pourquoi ne pas employer la fonction IsNumeric ou l'opérateur Like

V-G-1 - Fonction IsNumeric

La fonction IsNumeric renvoie une valeur de type boolén qui indique si une expression peut être interprétée comme un nombre et paraît très séduisante, mais...

Si on emploie cette fonction ainsi :

If IsNumeric(strpass) = False Then ChainePasOK = True

on se rend compte que le résultat ne correspond pas forcément à ce que nous pouvions penser. En voici quelques particularités contextuelles :

IsNumeric (sur mon system, français par défaut) :

- Bloque le point dans une chaîne car IsNumeric (123.45) renvoie Vrai, mais IsNumeric ("123.45") renvoie Faux et IsNumeric ("123,45") renvoie Vrai, ce qui est logique le point étant le séparateur numérique des nombres et la virgule étant, elle, interprétée comme le séparateur à travers la chaîne de caractères !

- Accepte 0,123e5

- Accepte 0,56d3

- Accepte 123€

- Refuse 123$.

- Refuse 123%.

- Accepte (123)

- Accepte &HC0

- ...

IsNumeric ne bogue pas et se comporte normalement par rapport à sa définition et aux choix de la langue et des paramètres système, mais peut causer des résultats inattendus si on ne prend pas en compte tous les paramètres.

V-G-2 - Opérateur Like

Nous pourrions envisager également, d'utiliser l'opérateur Like qui permet de comparer deux chaînes (Sting et Pattern) selon la syntaxe suivante :
Result = string Like pattern avec pattern pouvant être une suite de # qui correspondent alors à tout chiffre unique (de 0 à 9).
Mais, nous ne pourrions pas avec l'utilisation de # seul laisser passer le signe - et la virgule qui nous intéressent.

V-G-3 - Il en résulte que

On pourrait concevoir de mettre nos premiers filtres en place et de n'utiliser ces alternatives qu'ensuite, mais dans notre démarche, il était plus simple de construire selon nos besoins que de laisser un contexte non testé nous poser problème et des ambiguïtés dans nos choix.

VI - Liens utiles

Userform modal ou non, voyez le Tutoriel de SilkyRoad, notamment les paragraphes : III-A-1 affichage modal et III-A-2 affichage non modal.

Un Tutoriel très complet sur la manipulation des chaînes de caractèrespar SilkyRoad

Quelques fonctions VBA - Fonctions Texte par Heureux-oli

VII - Remerciements

Je remercie vivement :

Pierre Fauconnier, pour ses conseils techniques et idées d'addin.
Philippe Jochmans pour sa relecture technique.
Jacques_jean pour son travail de relecture et de correction, ainsi que ses suggestions.
L'équipe DVP qui fait que tout ça soit possible.

VIII - Téléchargement

Téléchargement 1 fichier avec macro. Testé sous Excel 2003 et 2007.

Obliger saisie numérique dans textbox - avec macro

Toutes les feuilles d'un classeur qui se révèleront protégées pour éviter les accidents, le sont sans mot de passe !