[VBA]Condition TextBox = Nombre positif

Résolu
Bonjour à tous,

Je suis en train de créer un formulaire en VBA pour Excel. Dans ce dernier se trouve une grande quantité de Textbox dont certaines (une 20aine) ne peuvent accueillir que des nombres positifs (ce sont des longueurs en mm) ou du vide si on ne remplit pas la case.

Pour ce faire, j'ai créer ce code :

Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If IsNumeric(TextBox1.Text) = False And TextBox1.Text <> "" Then
Cancel = True
MsgBox "La valeur rentrée n'est pas pas un nombre."
ElseIf TextBox1 < 0 Then
Cancel = True
MsgBox "La valeur rentrée n'est pas un nombre positif."
End If
End Sub

Et je le duplique ensuite pour chacune de mes textbox. J'obtiens le résultat escompté, mais je trouve cette programmation lourde : j'ai du recopier 20 fois ce code dans ma macro. Quelqu'un aurait-il une idée pour optimiser ce code ou pour éviter de le recopier 20 fois, si tant est qu'il y ait une solution plus optimale (ce que je pense) ?

D'avance merci pour votre aide.

Cordialement.

MA
Configuration: Windows XP
Internet Explorer 6.0

13 réponses

  1. Bonjour,

    j'ai rencontré lemême problème il y a quelques temps,
    jse fais un scan de tous les controls puis je regarde si le nom est textbox xx
    et je regarde si ce n'est pas vide ( on peut modifier )
    si cela ne correspond pas on quitte la procedure puis on place le focus sur l'intrus...
    bon courage.

    If IK > 1 Then
    For Each MyControl In Controls
    If Left(MyControl.Name, 7) = "TextBox" Then ' on lit un textbox
    If MyControl.Name="" then
    s = Chr(10) & "Manque une valeur" & Chr(10)
    suite = MsgBox(s, vbOKOnly)
    Userform1.Mycontrols.SetFocus
    Exit Sub
    End If

    End If
    Next
    End If
    3
    1. Le problème vient du fait que tu utilise un variant pour mycontrol2
      donc il ne possède pas la propriété .caption
      mycontrol2 est une variable qui contient "Lab...."
      mycontrol est un objet de la classe controls.
      je corrige comme suit....

      For Each mycontrol In Controls
      mycontrol2 = "Lab" & Mid(mycontrol.Name, 4, 100)
      If Left(mycontrol.Name, 3) = "Txt" Then ' on lit un textbox
      If IsNumeric(mycontrol.Text) = False And mycontrol.Text <> "" Then
      s = MsgBox("Vous n'avez pas rempli la case " & mycontrol2 & " avec une valeur numérique !", vbCritical, "Erreur")
      Exit Sub
      mycontrol.Name.SetFocus
      ElseIf mycontrol < 0 Then
      s = MsgBox("La valeur " & mycontrol2 & " ne peut pas être négative !", vbCritical, "Erreur")
      mycontrol.SetFocus
      Exit Sub
      Exit For
      End If
      End If
      Next

      et je te propose ce code ... retour sur le controle qui est en défaut.

      For Each mycontrol In Controls
      mycontrol2 = "Lab" & Mid(mycontrol.Name, 4, 100)
      If Left(mycontrol.Name, 3) = "Txt" Then ' on lit un textbox
      If IsNumeric(mycontrol.Text) = False And mycontrol.Text <> "" Then
      s = MsgBox("Vous n'avez pas rempli la case " & mycontrol2 & " avec une valeur numérique !", vbCritical, "Erreur")
      mycontrol.SetFocus
      Exit for


      ElseIf mycontrol < 0 Then
      s = MsgBox("La valeur " & mycontrol2 & " ne peut pas être négative !", vbCritical, "Erreur")
      mycontrol.SetFocus
      mycontrol.SetFocus
      Exit for

      End If
      End If
      Next

      A+
      1
      1. Je comprends le soucis...

        le problème c'est que l'utilisation de la boucle for each entraine un examen des objets
        dans l'ordre de création. et je ne pense pas qu'ilsoient tous créés ....label1, textbox1,label2,textbox2
        Ce qui limite les possibilités.

        il est possible d'utiliser mycontrol2 en tant qu'objet en écrivant

        Dim mycontrol2 As Control
        mais il n'aura jamais la propriété "caption" mais "value"

        dim mycontrol2 as object
        '...
        '....

        i=0
        For Each mycontrol In Controls

        set mycontrol2=controls.item(i)

        '...
        '...
        i=i+1 ' incrémente le controle
        next

        j'aimerai te soumettre une suggestion.
        lorsque la boucle for each lit un controle textbox : pourquoi lire le contenu d'un autre controle (le label)?
        Ne serait-il pas judicieux de faire référence à controltiptex
        ainsi il serait possible d'utiliser mycontrol.controltiptext
        et dans controltiptext tu écris ce que tu veux.

        sinon sans faire "d'usine à gaz" je ne vois pas
        1
        1. VBA ne gère pas la programmation objet et donc il n'y a pas d'autre solution que de faire de la programmation procédurale. Donc il n'est pas possible de faire autrement.
          0
          1. la réponse post 2 m'a laissé perplexe, je viens de vérifié

            on peut aussi écrire

            toujours dans le bouton de validation

            Private Sub Valider_Click()

            ' pour ecrire le contenu des textbox paramètre

            For Each mycontrol In Controls
            If Left(mycontrol.Name, 7) = "TextBox" Then ' on lit un textbox
            If mycontrol.Value = "" Then
            s = MsgBox(" vide ici dans " & mycontrol.name, vbCritical, "Erreur")
            Exit For
            End If

            End If
            Next

            End Sub
            0
            1. Merci à vous deux pour vos réponses.

              Je craignais que la programmation objet ne soit pas gérée par VBA, c'est le cas. Tant pis...

              @Bidouilleu_R
              Merci pour l'astuce. Je l'ai experimenté, l'adaptant à mes besoins... Ca a l'air de fonctionner, même si ça ne marche que lors de la validation du formulaire et non pas lors de la saisie des TextBox ; je vais donc combiner les 2. De plus, il va falloir que je modifie un peu le nom de mes textBox afin de différencier celles qui doivent répondre à la condition (les TextBox de longueur) et les autres qui n'ont pas à avoir de telles conditions.

              Encore merci pour votre aide à vous 2 et à bientôt.

              MA
              0
              1. une deuxième astuce

                pour pour gagner du temps il est possible d'ajouter....
                ce qui permet d'aller immédiatement sur le control en défaut

                For Each mycontrol In Controls
                If Left(mycontrol.Name, 7) = "TextBox" Then ' on lit un textbox
                If mycontrol.Value = "" Then
                s = MsgBox(" vide ici dans " & mycontrol.name, vbCritical, "Erreur")
                mycontrol.setfocus
                Exit For
                End If

                End If
                Next
                0
                1. Merci Bidouilleu_R, le programme fonctionne bien avec ce que j'ai fait.

                  Seule petite optimisation que j'ai tenté d'effectuer, c'est de remplacer le nom de la textbox (un peu rébarbatif) par le caption du Label qui lui est associé. J'ai tenté une petite astuce mais je ne comprends pourquoi ça ne fonctionne pas :

                  For Each mycontrol In Controls
                  mycontrol2 = "Lab" & Mid(mycontrol.Name, 4, 100)
                  If Left(mycontrol.Name, 3) = "Txt" Then ' on lit un textbox
                  If IsNumeric(mycontrol.Text) = False And mycontrol.Text <> "" Then
                  s = MsgBox("Vous n'avez pas rempli la case " & mycontrol2.Caption & " avec une valeur numérique !", vbCritical, "Erreur")
                  Exit Sub
                  mycontrol.Name.SetFocus
                  ElseIf mycontrol < 0 Then
                  s = MsgBox("La valeur " & mycontrol2.Caption & " ne peut pas être négative !", vbCritical, "Erreur")
                  mycontrol.SetFocus
                  Exit Sub
                  Exit For
                  End If
                  End If
                  Next

                  L'erreur semble venir de mycontrol2.Caption alors que mycontrol2 semble bien renvoyer ce que je désire....

                  Je tiens à préciser que toutes mes TextBox commencent par Txt et que tous mes Labels commencent par Lab...
                  Pour chaque TextBox Txt[nom], un Label Lab[nom] lui est associé avec [nom] identique, cela va de soi...

                  Si quelqu'un a une petite idée ^^

                  Bonne journée à tous !

                  MA
                  0
                  1. Merci pour ton explication Bidouilleu_R, je comprend mieux pourquoi il refusait de faire mon .Caption.
                    Merci également pour tes corrections : il n'y a plus aucun bug dans ce code et tout fonctionne de manière impecable !
                    Promis, c'est la dernière question et après, j'arrête de vous embêter :
                    N'y a-t-il pas moyen de transformer un Variant en Objet afin que je puisse au final utiliser mon .Caption ?

                    Exemple :
                    Le nom de ma Textbox est "TxtRisque".
                    Le nom du Label qui lui est associé est "LabRisque".
                    Le Caption du Label, donc LabRisque.Caption, est "Risque identifié".
                    Avec la méthode élaborée gràçe à toi, si je remplis mal, la MsgBox écrit : "La valeur LabRisque ne peut pas être négative !"
                    Ne pourrait-on avoir "La valeur Risque identifié ne peut pas être négative !" ?

                    Bah, si ce n'est pas possible, c'est pas grave : le code tel que tu m'as permis de l'avoir est déjà très bien XD.

                    Encore une fois, merci à tous pour l'aide que vous accordez aux plus nuls (ne soyons pas si méchants, on dira plutôt aux moins bons) en prenant sur votre temps : une fois plus calé en VBA, j'espère bien pouvoir moi aussi participer activement.

                    A bientôt.

                    MA
                    0
                    1. j'ai une idée mais il faut que je teste....
                      Pour information je ne considère pas que les autres sont nuls en ceci ou cela
                      Je dirai plutôt qu'ils prennent le chemin pour apprendre ou découvrir ce que d'autres ont vu avant...
                      je regarde et je te tiens au courant.
                      0
                      1. Mais c'est bien sûr !!!
                        Je n'avais pas du tout pensé à ta suggestion, pourtant simple, alors que j'avais utilisé l'équivalent avec des OptionButton dont je ne voulais pas retranscrire le .Caption tel quel dans mon tableur.

                        Merci encore une fois de plus Bidouilleu_R : ta dernière astuce me permet vraiment de faire tout ce que je voulais faire. Associer à l'autre bout de programme, j'ai vraiment qqch qui correspond en tous points à mes attentes.

                        Et pour couronner le tout, j'aurais appris qq trucs dans ce topic grace à tes explications.

                        Encore merci et bravo pour ces interventions.

                        A bientôt p-ê sur un autre topic !

                        MA
                        0
                        1. Ben! je suis content pour toi!

                          tu peux mettre résolu si ... tu pense que c'est résolu

                          Bonne journée.

                          R
                          0
                          1. Ne t'inquiète pas, c'est fait depuis hier : ta dernière astuce n'était que du bonus alors j'avais déjà résolu le Topic ;)

                            Encore merci et bonne soirée.

                            MA
                            0