VBA Gestion des événements dans une Interface implémentée par plusieurs classes de TextBox
Bonjour,
Je suis en train de créer une interface pour me simplifier la vie.
Celle-ci servira à contrôler les saisies dans les TextBox de mon Userform.
Pour cela, je me suis grandement inspiré de ce post
Pour l'exemple, on va considérer deux traitements différents, les TextBox impairs = numéro de sécurité sociale, les pairs : majuscules uniquement.
Voici mon code actuel :
Code de l'UserForm :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| Option Explicit
Dim TB_SS(30) As New cSecuSociale
Dim WithEvents TBevent_SS As cSecuSociale
Dim TB_NOMS(30) As New cMajuscules
Dim WithEvents TBevent_Nom As cMajuscules
Private Sub UserForm_Initialize()
Dim Ctrl As Control, i As Byte
For Each Ctrl In Me.Controls
If TypeOf Ctrl Is MSForms.TextBox Then
If i Mod 2 = 0 Then
Set TBevent_SS = New cSecuSociale
TB_SS(i).Add TBevent_SS, Ctrl
Else
Set TBevent_Nom = New cMajuscules
TB_NOMS(i).Add TBevent_Nom, Ctrl
End If
i = i + 1
End If
Next Ctrl
End Sub
Private Sub UserForm_Terminate()
Erase TB_SS
Erase TB_NOMS
End Sub |
L'interface nommée ITextbox :
Code:
1 2 3 4 5 6
| Option Explicit
Public Sub OnKeyDown(TextBox As MSForms.TextBox, KeyCode As MSForms.ReturnInteger, Shift As Integer)
End Sub
Public Sub OnKeyPress(TextBox As MSForms.TextBox, ByVal KeyAscii As MSForms.ReturnInteger)
End Sub |
Module de classe cSecuSociale
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| Option Explicit
Implements ITextBox
Private WithEvents T_Bx As MSForms.TextBox
Private T_Appel As ITextBox
Event KeyDown(TextBox As MSForms.TextBox, KeyCode As MSForms.ReturnInteger, Shift As Integer)
Public Sub Add(HEvent As cSecuSociale, TBox As MSForms.TextBox)
If Not HEvent Is Nothing And Not TBox Is Nothing Then
If T_Appel Is Nothing Then Set T_Appel = HEvent
If T_Bx Is Nothing Then
Set T_Bx = TBox
End If
End If
End Sub
Private Sub ITextBox_OnKeyDown(TextBox As MSForms.IMdcText, KeyCode As MSForms.ReturnInteger, Shift As Integer)
Select Case KeyCode
Case 96 To 105 'chiffres pavé numérique
If Shift = 1 Then KeyCode = 0
If Len(TextBox.Text) = 15 Then KeyCode = 0
Case 48 To 57 'chiffre touches clavier alphanumérique
If Shift = 0 Then KeyCode = 0
If Len(TextBox.Text) = 15 Then KeyCode = 0
Case 8, 9, 16, 46 'touches retour arrière, TAB, Shift, Suppr
'action à voir
Case Else
KeyCode = 0
End Select
End Sub
Private Sub T_Bx_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Call T_Appel.OnKeyDown(T_Bx, KeyCode, Shift)
End Sub
Private Sub ITextBox_OnKeyPress(TextBox As MSForms.IMdcText, ByVal KeyAscii As MSForms.ReturnInteger)
End Sub |
Module de classe cMajuscules
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| Option Explicit
Implements ITextBox
Private WithEvents T_Bx As MSForms.TextBox
Private T_Appel As ITextBox
Event KeyPress(TextBox As MSForms.TextBox, KeyAscii As MSForms.ReturnInteger)
Public Sub Add(HEvent As cMajuscules, TBox As MSForms.TextBox)
If Not HEvent Is Nothing And Not TBox Is Nothing Then
If T_Appel Is Nothing Then Set T_Appel = HEvent
If T_Bx Is Nothing Then Set T_Bx = TBox
End If
End Sub
Private Sub ITextBox_OnKeyPress(TextBox As MSForms.IMdcText, ByVal KeyAscii As MSForms.ReturnInteger)
Select Case KeyAscii
Case 32 'espace
KeyAscii = 0
Case 45 'trait d'union
If Len(TextBox.Text) = 0 Then KeyAscii = 0
Case 65 To 90 'majuscules
Case 97 To 122 'minuscules
KeyAscii = KeyAscii - 32
Case Else
KeyAscii = 0
End Select
End Sub
Private Sub T_Bx_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Call T_Appel.OnKeyPress(T_Bx, KeyAscii)
End Sub
Private Sub ITextBox_OnKeyDown(TextBox As MSForms.IMdcText, KeyCode As MSForms.ReturnInteger, Shift As Integer)
End Sub |
Au départ, avant de me lancer dans ce projet, j'imaginais créer, depuis l'userForm, une unique variable tableau globale de type ITextbox qui comprendrait tous mes textbox.
Puis, la répartition entre chaque type de classe se serait faite dans l'initialize.
En "faux code", voici ce que j'imaginais faire et qui (bien entendu) ne fonctionne pas :
Faux code de l'UserForm :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Option Explicit
Dim TB(30) As ITextbox
Private Sub UserForm_Initialize()
Dim Ctrl As Control, i As Byte
For Each Ctrl In Me.Controls
If TypeOf Ctrl Is MSForms.TextBox Then
If T Mod 2 = 0 Then
Set TB(i) = New cSecuSociale
TB(i).Add Ctrl
Else
Set TB(i) = New cMajuscules
TB(i).Add Ctrl
End If
i = i + 1
End If
Next Ctrl
End Sub
Private Sub UserForm_Terminate()
Erase TB
End Sub |
Pensez-vous cela réalisable tout de même?
Parce qu'en fait, à terme, je vais avoir une dizaine de "types" de textbox, donc une dizaine de classes et donc, une dizaine de variables tableaux à déclarer dans l'UserForm...
Une interface capable de gérer tous types de saisie dans les textbox d'un userform
Bonjour,
Voici la démarche qui m'a poussé à poursuivre ce projet.
En cherchant à intercepter les événement Exit et Enter de textbox construit dynamiquement, je suis tombé sur une solution utilisant l'API ConnectToConnectionPoint SOURCE . La solution de sylkiroad sur DVP ne me convenait pas car beaucoup trop gourmande en ressources...
En faisant mes tests sur un UserForm, je me suis rendu compte que la plus grande difficulté de maintenance de cette méthode réside dans les Attribute VB_UserMemId cachés.
En effet, à chaque copié-collé du module de classe, à chaque suppression, le risque est grand de supprimer cet attribut indispensable au fonctionnement.
De là, je suis parti à la recherche d'une solution qui permettrait d'éviter ces "accidents".
Je suis tombé sur ce tutoriel expliquant le principe de l'interface.
En creusant un peu (Source 1 --- Source 2), j'ai trouvé l'idée assez sympa de pouvoir bénéficier :
> d'une classe gérant les procédures communes (l'interface iTextBox dans le classeur joint)
> d'une classe par type de textbox (les classes cSecuSSociale et cMajuscules dans le classeur joint)
Ainsi, l'on peut facilement gérer les différents types de saisie possible et imaginable dans un userForm.
Il suffit, pour cela, d'insérer un nouveau module de classe (cf module de classe Modele dans le classeur joint), et d'y placer les contrôles souhaités en sortie, en entrée ou dans les événements normalement gérés par ce type de contrôle.
Pièce jointe 209247
Voici donc le résultat.
Merci de bien vouloir me donner vos avis à ce sujet.
Tant au niveau du fond que de la forme du code.
A++