Cancel = true ne fonctionne pas sur sortie textbox

Bonjour,

Avez vous essayer les onglets de USF ?

Un USF principal avec le menu de vos boutons et les onglets pour remplacer vos différents USF.

Ou bien l'idée de mon application QCM USF où chaque USF du jeu ne sont qu'en fait des frames d'un seul que je masque où pas en fonction des demandes.

Seule chose à faire pour une gestion simplifiée : créer chaque frame les unes à côté des autres sur un USF "immense" et par code les placer les une au dessus des autres en les masquant et en réduisant la taille du USF général.

@ bientôt

LouReeD

Bonjour à tous,

Sur le problème initial, le problème semble bien lié au fait que j'utilise les formulaires en non modal.

Bon, l'utilisation de Exit n'est pas judicieuse. Privilégier AfterUpdate.

Voici un cadeau :

Dans un module que vous nommerez RegularExpressions vous coller le code ci-dessous :

'@ModuleDescription "Gestion des Expressions R�guli�res."
'@Folder "System"
'SOURCE: www.TheSpreadsheetGuru.com/the-code-vault

Option Explicit
'----------------- CONSTANTES MODULE REGEXP
Private Const CODE_POSTAL_PATTERN As String = "^\d{5}$"
Private Const DATE_FORMAT_PATTERN As String = "([\[\(])?( ?)(\d{4})( ?)([\]\)])?$" ' // Recherche d'une date entre parenthèses ou crochets dans une chaine
Private Const GENERAL_PHONE_PATTERN As String = "^((\+33\s?(\(0\))?\s?|0)[1-5](\s?\d{2}){4}|(\+33\s?(\(0\))?\s?|0)(6|7)(\s?\d{2}){4})$"
Private Const LAND_LINE_PHONE_PATTERN As String = vbNullString
Private Const LINUX_FORMAT_PATTERN As String = "[._]" ' // Recherche des caractères LINUX pour le renommage d'un fichier
Private Const MAIL_ADDRESS_PATTERN As String = "[\w_.+-]+@[\w-]+\.[\w-]+" ' // Recherche d'adresse de courriel dans une chaine
Private Const MAIL_PATTERN As String = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$" ' // Valide une adresse de courriel
Private Const MOBILE_PHONE_PATTERN As String = "^(\+33\s?(\(0\))?\s?|0)(6|7)(\s?\d{2}){4}$" ' // Valide un numéro de téléphone.
Private Const WEB_ADDRESS_PATTERN As String = "(https?://|ftp://|www.)([\w_.+-]+)*([\w]+)" ' // Recherche de lien Web dans une chaine
Private Const WINDOWS_FORMAT_PATTERN As String = "[\\<>\/:\*?\|]" ' // Suppression des mauvais caractères pour le nommage d'un fichier

Public Enum vaRegExpPattern
    CodePostalPattern = 1
    DateFormatPattern = 2
    GeneralPhonePattern = 3
    LandlinePhonePattren = 4
    LinuxFormatPattern = 5
    MailAdressPattern = 6
    MailPattern = 7
    MobilePhonePattern = 8
    PhoneNumberPattern = 9
    WebAdressPattern = 10
    WindowsFormatPattern = 11
End Enum

'@Description "Valide une entrée selon un pattern bien définie."
Public Function IsValidEntry(ByVal Pattern As vaRegExpPattern, Value As Variant) As Boolean
    Dim RegEx As Object
    Set RegEx = CreateObject("VBScript.RegExp")
    Dim TempString As String
    TempString = Choose(Pattern, CODE_POSTAL_PATTERN, _
                        DATE_FORMAT_PATTERN, _
                        GENERAL_PHONE_PATTERN, _
                        LAND_LINE_PHONE_PATTERN, _
                        LINUX_FORMAT_PATTERN, _
                        MAIL_ADDRESS_PATTERN, _
                        MAIL_PATTERN, _
                        MOBILE_PHONE_PATTERN, _
                        WEB_ADDRESS_PATTERN, _
                        WINDOWS_FORMAT_PATTERN)

    With RegEx
        .Pattern = TempString
        .IgnoreCase = True
        .Global = False
    End With

    IsValidEntry = RegEx.Test(Value) = True
    If Not RegEx Is Nothing Then Set RegEx = Nothing
End Function

Public Function IsValidPhone(Value As String) As Boolean
    With CreateObject("VBScript.RegExp")
        .Pattern = "^((\+33\s?(\(0\))?\s?|0)[1-5](\s?\d{2}){4}|(\+33\s?(\(0\))?\s?|0)(6|7)(\s?\d{2}){4})$"
        .IgnoreCase = True
        .Global = False

        IsValidPhone = .Test(Value)
    End With
End Function

Public Function IsValidMobilePhone(Value As String) As Boolean
    With CreateObject("VBScript.RegExp")
        .Pattern = "^(\+33\s?(\(0\))?\s?|0)(6|7)(\s?\d{2}){4}$"
        .IgnoreCase = True
        .Global = False

        IsValidMobilePhone = .Test(Value)
    End With
End Function

Public Function IsValidLandlinePhone(Value As String) As Boolean
    With CreateObject("VBScript.RegExp")
        .Pattern = "^(\+33\s?(\(0\))?\s?|0)[1-5](\s?\d{2}){4}$"
        .IgnoreCase = True
        .Global = False

        IsValidLandlinePhone = .Test(Value)
    End With
End Function

Ensuite vous virez la procédure Tbx_UsersModification_NewTel_Exit

Vous sélectionnez la procédure : Tbx_UsersModification_NewTel_BeforeUpdate, et vous y coller le code ci-dessous :

Private Sub Tbx_UsersModification_NewTel_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    With Tbx_UsersModification_NewTel
        If Not (RegularExpressions.IsValidEntry(vaRegExpPattern.GeneralPhonePattern, .Value)) Then
            Beep
            Cancel = True
            .SelStart = 0
            .SelLength = Len(.Value)
            End If
        End With
    End Sub

Voilà vous aurez votre vérification avant la mise à jour du contrôle.

Et comme vous pouvez le constater, vous pourrez faire d'autres validation Mail, code postal etc...

  • Maintenant est-il bien judicieux d'utiliser des noms de contrôles à rallonge ?
  • Évitez aussi la notation Hongroise qui ne fait qu’alourdir le code. OldPhone et NewPhone sont assez parlant non ?
  • Vous devriez éviter de nommer vos contrôles avec des Underscores cela prête à confusion avec les méthodes des contrôles.

Merci à tous les deux de vos réponses. Précision: je suis retraité et il y encore quelques mois, je ne connaissais pas grand chose en vba. je n'en connais probablement pas beaucoup plus aujourd'hui, mais çà me permet de m'amuser et pour m'occuper, je me suis lancé dans ce petit développement de gestion de comptes. çà me permet de faire tourner les neurones. Donc j'ai regardé vos deux propositions. Lou Reed, pas sur que je puisse utiliser cela pour mon projet. J'ai en effet pas mal de formulaires car mon projet est bien avancé. çà va de la gestion des tiers et catégories à la prévision de trésorerie, en passant par les comptes d'emprunt, etc...

Jean-Paul, j'ai du relire plusieurs fois le code avant de commencer à comprendre. donc un module qui enregistre les formats d'expression à contrôler et les fonctions de contrôle. je ne comprends pas le public ENum, ou plutôt, je ne comprends pas comment cette liste est utilisée. je ne connaissais pas beep non plus.

votre cadeau est bien intéressant. je creuse tout çà, mais çà me semble bien être la bonne solution.

Sur la notation hongroise, elle me permet de me repérer, de même que les noms à rallonge et les underscore. par exemple, si j'ai un textbox code postal dans un userform banque, ou un userform tiers, ou utilisateur, je sais en faisant tbx_banque_cpostal ou je suis. mais promis, je vais améliorer çà aussi. Merci à vous deux et dés que j'ai fini de tester la solution, je passerai le sujet en cloturé. A bientôt

PS. J'ai terminé la structure des dossiers dans rubberduck. c'est vraiment pratique.

re,

je suis allé voir enum. je pense avoir compris. j'utilise différentes couleurs pour mes userform, définies dans une classe config. je pourrais donc avoir dans un module colors des private const redcolor as long = xxxxx, private const greencolor as long = yyyy et faire un public enum vaColors. Cà, ok. par contre je ne vois pas à quel moment on fait référence à cette liste.

Autre question isvalidentry semble balayer tous les formats. est ce que pattern est un élément de enum ? et pourquoi repasser le format dans les fonctions ?

merci

Bonjour,

Je me permets d’intervenir pour répondre à vos interrogations. Tout d’abord j’ai +1 le message de Jean-Paul car ce sont d’excellents conseils, que j’appuie également. Pas de soucis, vous avez tout le temps d’apprendre.


je ne comprends pas le public Enum

Enum permet de créer une liste de paramètres prédéfinis, en faisant correspondre des noms que l’on comprend à des numéros qui eux seront utilisés par le code. C’est un outil assez pratique quand on a beaucoup de “nombres magiques” comme paramètres. Cela permet de les nommer. Par exemple VBA utilise des enums. Quand vous utilisez une MsgBox et que vous écrivez MsgBox(…, vbYesNo), vbYesNoest un enum qui correspond à la Valeur 4 (qui sera utilisée par le code). Les correspondances ici.

Cf. VBA Enums (en anglais, utilisez un traducteur si besoin)


Pour la notation des variables dans le code, il y a plusieurs écoles. Cependant comme souligné par Jean Paul, on est limité par 1 fait : en VBA le “_” est utilisé par le code. On aura donc tendance à s’orienter vers le pascal case ou le camel case pour le nommage des variables/fonctions.

Càd que pour séparer les mots dans la variable “nombre d’eleves”, au lieu d’écrire « nombre_eleves » on va plutôt écrire “nombreEleves” ou “NombreEleves”. Personellement pour m’y retrouver je suis la méthode suivante :

Nom des subs et des fonctions avec une Majuscule en 1e lettre, nom des variables avec une minuscule en 1e lettre.

Quant à la notation hongroise (préfixe de type) moi aussi je n’aime pas trop mais je sais qu’elle est très présente en VBA, même si aujourd’hui c’est vu comme vétuste. Le problème c’est que pour s’en passer dans les userforms ce n’est pas évident, et moi aussi j’utilise souvent un préfix pour indiquer si une variable est une textbox, label, etc. car c’est compliqué autrement (programmation plus avancée par toujours nécessaire).

De toute façon si vous utilisez Rubberduck il vous indiquera ce genre de choses, c’est un excellent outil.

Bonjour à tous,

Autre question isvalidentry semble balayer tous les formats. est ce que pattern est un élément de enum ?

L'utilisation des énumération est là juste pour simplifier le codage exemple vous voulez vérifier si les données d'un champ texte pour une adresse de courriel sont valides vous allez encoder :

000002

Vous pouvez voir que des propositions sont faite, en fonction du choix la fonction IsValidEntry vérifiera que les valeurs entrées sont conforme.

On ne peut attribuer que des nombres aux énumérations contrairement à d'autres langages. Ce qui explique l'utilisation de Choose qui récupère une chaine de caractères en rapport avec l'index.

ps. Ici j'utilise un bloc With qui ne sert à rien

re, et encore merci. rapide et efficace. Pensez Access : j'aurais du le voir.

A nouveau, Jean-Paul, tu me sors du pétrin. Quand j'ai vu cette annotation, je suis retourné voir les questions que j'avais posées et bingo. je retrouve Jean-Paul dans les réponses. donc, un trés grand merci. Tu vois, je suis toujours sur le même projet. je progresse lentement mais surement. j'ajoute des fonctionnalités, des contrôles supplémentaires en saisie comme dans le cas présent. bref, je m'amuse.

merci aussi à Saboh et Lou Reed. je mets cette solution en place. Amicalement à tous

Re

Je me suis rendu compte que certains Pattern dans le module RegularExpression n'était pas généraux, mais adaptés à des cas particuliers dans mes projets.

J'ai donc refait le ménage. Voici une version plus simplifiée et mieux adaptée aux cas généraux :

'@ModuleDescription "Gestion des Expressions Régulières."
'@Folder "System"
'SOURCE: www.TheSpreadsheetGuru.com/the-code-vault

Option Explicit

Public Enum vaRegExpPattern
    CodePostalPattern = 1                        ' // Vérifie la validité d'un code postal.
    GeneralPhonePattern = 2                      ' // Vérifie la validité d'un numéro de téléphone fixe.
    LandlinePhonePattren = 3                     ' // Vérifie la validité d'un numéro de téléphone fixe.
    LinuxFormatPattern = 4                       ' // Vérifie la validité d'une chaine pour le format LINUX.
    MailPattern = 5                              ' // Vérifie la validité d'une adresse de courriel.
    MobilePhonePattern = 6                       ' // Vérifie la validité d'un numéro de téléphone mobile.
    WebAdressPattern = 7                         ' // Vérifie la validité d'un lien  Web dans une chaine.
    WindowsFormatPattern = 8                     ' // Vérifie la validité du nom de fichier sous Windows.
End Enum

'----------------- CONSTANTES MODULE REGEXP
Private Const CODE_POSTAL_PATTERN As String = "^\d{5}$"
Private Const GENERAL_PHONE_PATTERN As String = "^((\+33\s?(\(0\))?\s?|0)[1-5](\s?\d{2}){4}|(\+33\s?(\(0\))?\s?|0)(6|7)(\s?\d{2}){4})$"
Private Const LAND_LINE_PHONE_PATTERN As String = "^(\+33\s?(\(0\))?\s?|0)[1-5](\s?\d{2}){4}$"
Private Const LINUX_FORMAT_PATTERN As String = "^[a-zA-Z0-9._-]+$"
Private Const MAIL_PATTERN As String = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$" ' //
Private Const MOBILE_PHONE_PATTERN As String = "^(\+33\s?(\(0\))?\s?|0)(6|7)(\s?\d{2}){4}$"
Private Const WEB_ADDRESS_PATTERN As String = "(https?://|ftp://|www.)([\w_.+-]+)*([\w]+)"
Private Const WINDOWS_FORMAT_PATTERN As String = "^[^\\/:*?""<>|]+$"

'@Description "Valide une entrée selon un pattern bien définie."
Public Function IsValidEntry(ByVal Pattern As vaRegExpPattern, Value As Variant) As Boolean
    Dim RegEx As Object
    Set RegEx = CreateObject("VBScript.RegExp")
    Dim TempString As String
    TempString = Choose(Pattern, _
                        CODE_POSTAL_PATTERN, _
                        GENERAL_PHONE_PATTERN, _
                        LAND_LINE_PHONE_PATTERN, _
                        LINUX_FORMAT_PATTERN, _
                        MAIL_PATTERN, _
                        MOBILE_PHONE_PATTERN, _
                        WEB_ADDRESS_PATTERN, _
                        WINDOWS_FORMAT_PATTERN)

    With RegEx
        .Pattern = TempString
        .IgnoreCase = True
        .Global = False
    End With

    IsValidEntry = RegEx.test(Value) = True
    If Not RegEx Is Nothing Then Set RegEx = Nothing
End Function

J’aimerais bien des retour si problèmes de validations pour que je puisse l'adapter.

re, lou reed, je reviens sur l'idée d'un multipages. il y a peut-être quelque chose à tenter malgré le nombre de formulaires. j'ai fait quelques tests et on peut mettre un multipage dans un autre multipage, donc menu, sous menus... je teste çà. merci

rebonjour,

Aprés tests :

Loureed : le multipages, çà peut le faire, mais là j'aurais trop d'adaptations à faire, dommage

jean-paul, le code avec beforeupdate fonctionne nickel, en modal comme en non modal. j'ai testé codecpostal, téléphone et mail. mais si je remplace beep par un msgbox d'alerte, je perds le focus et la sélection du texte. le problème semble donc venir plus de msgbox quelque soit l'endroit ou je le mets.

Merci à tous

précisions : j'ai d'abord testé avec isvalidentry, donc sans message d'alerte , puis avec les procedures spécifiques isvalidCPostal,.. avec et sans message d'alerte.

Bonsoir à vous trois !

Là vous m'avez perdu ! Que ce soit les REGEXP ou Butterflyduck machin truc... je n'arrive plus à suivre bien que je pense passé à côté de quelque chose de grand !

@ bientôt

LouReeD

Re,

mais si je remplace beep par un msgbox d'alerte, je perds le focus et la sélection du texte.

Un exemple de code pour la Méthode AfterUpdate que vous utiliser, que je puisse voir cela. Merci

bonjour,

dans les exemples donnés, on était sur beforeupdate, c'est ce que j'ai fait

le code de la fonction pour le code postal : Public Function IsValidCpostal(Value As String) As Boolean

capture d ecran 2025 04 09 101132

le code du userform (avec beforeupdate qui était proposé)

capture d ecran 2025 04 09 102215

dans ce cas, avec beep, le focus et visible et reste sur le textbox, avec le msgbox, le focus n'est plus visible

et du coup, je viens de tenter avec afterupdate de la manière suivante:

capture d ecran 2025 04 09 102346

dans cas, le focus passe sur le textbox suivant, et même chose, si je mets msgbox en commentaire, le focus reste sur le textbox.

tout se passe un peu comme si msgbox faisait sortir de la procédure

merci de ton aide

Bonjour,

Vous avez remarqué que la méthode AfterUpdate n'a pas de paramètre Cancel ? Cela devrais vous mettre la puce à l'oreille non ?

Donc dans l'ordre si je ne me trompe pas nous avons :

  • Enter
  • KeyDown
  • KeyPress
  • Change
  • KeyUp
  • BeforeUpdate
  • AfterUpdate
  • Exit

Donc toute vérification doit être faites avant AfterUpDate après c'est trop tard pour cela.

Cela ne viens pas de la boite de message.

Pensez mettre le code entre balise </> en pas sous forme d'image.

bonjour,

oui, je sais que afterupdate n'a pas de paramétre cancel. simplement j'ai pensé que c'était une suggestion, donc j'ai essayé afterupdate. maintenant si ce ,'est pas le msgbox qui me perturbe, je ne vois pas d'où cela peut venir. merci de l'astuce pour copier le code.

voila donc le code:

Public Function IsValidCpostal(ByVal Value As String) As Boolean
With CreateObject("VBScript.RegExp")
.Pattern = "^\d{5}$"
.IgnoreCase = True
.Global = False

IsValidCpostal = .Test(Value)
'If Not IsValidCpostal Then MsgBox "pas bon"
End With
End Function

et dans le userform

Private Sub Tbx_UsersModification_NewCpostal_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    With Tbx_UsersModification_NewCpostal
        If Not (ControleSaisies.IsValidCpostal(Tbx_UsersModification_NewCpostal.Value)) Then
             'MsgBox "pas bon"
            Beep
           Cancel = True
            .SelStart = 0
            .SelLength = Len(.Value)
            End If
        End With
End Sub

merci

Les aléas d'Excel...

voici chez moi :

Private Sub txt1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    With txt1
        If Not IsValidCpostal(.Value) Then
            MsgBox "Pas glop, pas Glop"
            Cancel = True
            .SelStart = 0
            .SelLength = Len(.Value)
        End If
    End With
End Sub

Public Function IsValidCpostal(ByVal Value As String) As Boolean
    With CreateObject("VBScript.RegExp")
        .Pattern = "^\d{5}$"
        .IgnoreCase = True
        .Global = False

        IsValidCpostal = .Test(Value)
        'If Not IsValidCpostal Then MsgBox "pas bon"
    End With
End Function

C'est sensiblement pareil non ? Et pour les résultats :

Après appuis sur la touche entrée :

000006

Après clic sur le bouton OK :

000005

Il faut peut-être nettoyer le classeur.

Puisque vous utilisez Rubberduck il existe dans les paramètres généraux les touches de raccourcis pour effectuer certaines opérations.

Faite un essais sur vos déclarations à rallonge du style

Tbx_UsersModification_NewCpostal

Vous mettez le curseur dessus puis CTRL + R et hop tout les éléments sont renommés d'un seul coup et ce sera mieux à la lecture.

Bon faites une sauvegarde avant on ne sait jamais...

bonjour,

merci Jean-Paul, j'ai commencé le nettoyage du classeur et du coup, je modifie les noms au fur et à mesure. j'en ai pour un moment. on verra bien. mais si ce n'est pas msgbox, il reste la piste du mode modal/non modal. est ce que ton code fonctionne dans les deux cas?

Bonsoir,

Effectivement cela pose problème si la fenêtre est en mode non Modal.

Encore un mystère d'Exce.

Rechercher des sujets similaires à "cancel true fonctionne pas sortie textbox"