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 FunctionEnsuite 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 SubVoilà 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 :
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 FunctionJ’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
le code du userform (avec beforeupdate qui était proposé)
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:
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 Functionet 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 Submerci
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 FunctionC'est sensiblement pareil non ? Et pour les résultats :
Après appuis sur la touche entrée :
Après clic sur le bouton OK :
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_NewCpostalVous 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.