Module de classe : débogage complexe (migraineux s'abstenir !)
Bonjour,
Dans le fichier joint, les données sont fictives.
Dans ce fichier, il y a beaucoup de choses... C'est un peu le bordel car le truc est beaucoup plus complexe qu'il n'y parait, mais pour mon problème on peut résumer le truc à ceci :
2 UserForm seulement nous nous intéressent usfAcc et usfSaisie
Dans usfSaisie un module de classe contrôle les TextBox et plus particulièrement les tb2 et tb3 (Nom et Prénom) La classe est censé gérée la mise en majuscule (UCase) ou pour les prénoms une autre fonction du même genre...
Dans un premier temps vous fermerez le Userform Accueil par la croix de fermeture puis vous irez dans la feuille BD.
En cliquant sur le bouton vous afficherez le UserForm Saisie. Dans ce usfSaisie en cliquant sur "Nouveau" on pourrait créer un nouvel enregistrement.
En cliquant sur la zone Nom puis en tapant quelques lettres, on voit que le module de classe fait son boulot : Le nom se met en majuscule...
On arrêtera là l'expérience : je ne suis pas certain qu'on puisse aller jusqu'à la validation de toute la saisie...
Il en va de même si on entre en modification, Tout tentative de taper une minuscule dans la zone Nom se solde par une intervention de la classe et une remise en majuscule. Tout va bien.
Il existe divers autres moyens de provoquer l'affichage du UserForm.
En passant par la feuille Accueil : Si on clique sur l'étiquette "Saisie Code", on simule l'entrée d'un code barre dans le TextBox et le UserForm fonctionne correctement.
Mais c'est là ou est le problème : Si dans le usfAcc on saisie un nouveau CodeBarre (inexistant : p.e. 123456789 ) directement dans le TextBox on entre dans le usfSaisie : Théoriquement YAPUKA saisir le nom du bénéficiaire, mais là visiblement la classe ne fonctionne pas : Pourquoi ?
Merci.
Bonjour Galopin01
Je fais une revue de code tel que je la sens avec ce que je pressens, mais attention je ne suis pas un expert.
Le problème c'est que la saisie sur mon poste dans usfAcc fait redémarrer Excel : BUG Complet.
dans l'événement TB1_Change de usfAcc est appelé Main.ShowSaisie qui instancie 9 fois la classe classeTB alors que usfAcc n'a qu'une seule textbox. Est-ce normal?
Pour la seule classe classeTB à instancier, le retour se fait par TBox_Change qui appelle ConvertStr qui ne fait appelle qu'à usfSaisie: est-ce bien normal? puisque on vient de usfAcc.
Quand on instancie une Textbox avec ClasseTB ne faut t'il pas donner le nom de la forme s'y référant : j'ajouterais bien dans la classeTB l'origine du userform auquel appartient le Textbox.
Ensuite il faudra(it) faire un Select case du Userform d'appartenance dans les fonctions ShowSaisie et ConvertStr
J'espère que j'ai été clair et que tu pourras poursuivre car je n'ai pas envie de prendre une migraine.
Bonne chance
bonjour,
Oui j'aurai du le remarquer la classe s'applique également à usfAcc alors que ce n'est pas ce qei est souhaité !
Je vais restreindre le champs d'application à usfSaisie.
Merci
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bonjour Galopin,
A priori ton problème ne vient pas de la classe mais de la non disponibilité de l'événement Change, du fait à mon avis, que la procédure Change du usfAcc n'est pas terminée, tant que que l'usfSaisie n'est déchargé.
Private Sub TB1_Change()
Dim i%
If Len(Me.tb1) = 9 Then
i = Split(RetR(Me.tb1))(0)
If i < [rBD].Rows.Count Then '<= ??
Me.Hide
On Error GoTo GESTERR
' CBEN = CLng(Me.TB1) ' ???????????????,
ShowSaisie CLng(Me.tb1)
Else ' New CodeB
Me.Hide
CBEN = CLng(Me.tb1)
ShowSaisiebonjour,
Ça me semblait aussi très vraisemblable. Mais j'ai là 2 ou 3 problèmes fondamentaux :
1- J'ai remplacé Me.Hide par Unload Me et j'ai toujours le même problème !
2- Malgré tout comme ma classe n'tait pas censée couvrir les TextBox de usfAcc j'ai essayé de déclarer différemment cette classe pour qu'elle ne travaille que sur le usfSaisie. Mais comme je maitrise très mal les classes je n'y arrive pas.
3- Comment puis-je modifier cette déclaration pour faire en sorte que usfAcc ne se sente pas concerné ?
J'ai essayé de déclarer cette classe dans le usfSaisie comme je fait parfois dans quelques usf très simple, mais pour le coup plus rien ne marche quel que soit le mode d'entrée dans le usf... Je suppose que c'est un problème de syntaxe.
Il y a 9 TextBox à prendre en charge dans cette classe nommé tb1 à tb9 + 1 TextBox hors norme appelé "TBBJ" qui n'a pas besoin d'être déclaré (il a vocation à disparaitre ultérieurement et ne sert qu'au débogage.
Es-tu capable de me faire une déclaration qui tienne la route ?
Merci
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bonjour,
Pour résoudre le problème de l'événement Change, une solution possible :
Private Sub TB1_Change()
Dim i%
If Len(Me.tb1) = 9 Then
i = Split(RetR(Me.tb1))(0)
If i < [rBD].Rows.Count Then '<= ??
'Me.Hide
On Error GoTo GESTERR
' CBEN = CLng(Me.TB1) ' ???????????????,
Application.OnTime Now + TimeValue("00:00:01"), "'ShowSaisie""" & CLng(Me.tb1) & """'"
'ShowSaisie CLng(Me.TB1)
Else ' New CodeB
'Me.Hide
CBEN = CLng(Me.tb1)
Application.OnTime Now + TimeValue("00:00:01"), "ShowSaisie"
End If
Unload Me
End If
Exit Sub
GESTERR:
MsgBox "Erreur non gérée !"
End SubComment puis-je modifier cette déclaration pour faire en sorte que usfAcc ne se sente pas concerné ?
De tout façon, usfAcc n'est pas concerné puisque la variable associée aux événements de la classe ne concerne que les TextBox de usfSaisie.
Cela dit, il aurait été plus logique d'intégrer le module ConvertStr dans la classe. Ci-dessous proposition de modif :
Option Explicit
'# Instance de la clase
Public instance_TBox As Object
'# Formulaire appelant
Public USF As Object
Public WithEvents TBox As MSForms.Textbox
Private Sub TBox_Change()
Dim i%
i = Mid(TBox.Name, 3)
ConvertStr i
End Sub
Private Sub TBox_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Dim i%
i = Mid(TBox.Name, 3)
Select Case i
Case 1, 7, 8
'on ne peut pas taper autre chose que des chiffres
Select Case KeyAscii
Case Is < 48, Is > 57
KeyAscii = 0
End Select
End Select
End Sub
Sub ConvertStr(i%)
Dim Arr
With USF
Select Case i
Case 2
.Controls("TB" & i) = UCase(.Controls("TB" & i))
Case 3
If InStr(.tb3.Value, "-") > 0 Then
Arr = Split(.tb3, "-")
.tb3 = Arr(0) & "-" & StrConv(Arr(1), vbProperCase)
Else
.tb3 = StrConv(.tb3.Value, vbProperCase)
End If
End Select
End With
End SubEt pour éviter un tableau prédéfini à l'avance pour stocker les instances, on stocke l'instance dans l'instance elle-même.
Sub ShowSaisie(Optional i& = 0)
Dim k
Dim Textbox As ClasseTB
For k = 1 To 9
Set Textbox = New ClasseTB
Set Textbox.instance_TBox = Textbox
Set Textbox.USF = usfSaisie
Set Textbox.TBox = usfSaisie.Controls("tb" & k)
Next k
.......Bon désolé mais là tu m'as un peu perdu... Cela me parait bien compliqué pour le mécréant que je suis !
Je pensais à un truc plus simple que j'utilise parfois ou la classe est déclarée dans Initialize du Userform et c'est tout, mais sur ce coup je n'arrive pas à l'adapter.
Bon c'est pas grave mais sur cette appli il est essentiel que le usfSaisie puisse être appelé par une saisie de CodeBarre depuis le usfAcc. Vu que sur cette appli il n'y a pas une grande quantité d'appel à la classe, je vais revenir aux bons vieux Events traditionnels....
Merci encore.
A+
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Il est vrai que ce sera plus simple. Mais il n'empêche qu'il faut terminer la procédure TB1_change avant d'afficher l'usf_Saisie sinon l'événement Change ne sera pas disponible (classe ou non) dans l'usf_Saisie. C'est pourquoi j'ai utilisé Application.Ontime dans ma proposition.
J'ai carrément supprimé le Me.Hide et je l'ai remplacé par Unload Me comme c'est asynchrone ça n'empêche toutefois pas le chargement du usfSaisie et la transmission de la variable. Ça évite le Ontime avec lequel j'ai également souvent des démélés ombrageux...
[EDIT] : "Je suis un peu étonné par ce que tu dis : L'évènement change ne sera pas disponible..." Ce n'est pourtant pas pour rien qu'il existe une commande Hide qui permet bien souvent de passer la main d'un UserForm à l'autre sans avoir à les décharger.
On peut ainsi passer d'un usfClient à un autre usf qui permet de visualiser ses commandes puis revenir à la liste des clients... Il y a là quelque chose qui doit m'échapper !
A+
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Je suis un peu étonné par ce que tu dis : L'évènement change ne sera pas disponible..."
C'est ce que j'ai constaté.
Ce n'est pourtant pas pour rien qu'il existe une commande Hide qui permet bien souvent de passer la main d'un UserForm à l'autre sans avoir à les décharger.
On peut ainsi passer d'un usfClient à un autre usf qui permet de visualiser ses commandes puis revenir à la liste des clients... Il y a là quelque chose qui doit m'échapper !
Normalement oui. Mais il semble que la non terminaison de la procédure TB1_Change bloque bien la disponibilité de l'événement Change. Le "Unload Me" ne termine pas la procédure.
Ça c'est fort "Le "Unload Me" ne termine pas la procédure" et ne libère pas l'évènement Change !
C'est bien possible en effet mais dans ce cas ce serait spécifique à l'évènement Change ? Car j'ai joué bien souvent au jeu de chaise musicale d'un USF à l'autre, mais il se peut que ce soit avec des boutons ou des évènements Click...
Quoi qu'il en soit même en supprimant la classe je n'arrive toujours pas à provoquer un évènement Change après une saisie de usfAcc j'ai le même phénomène qu'avec la classe. Ça m'embête un peu car je déteste jouer avec OnTime mais j'ai bien peur d'être obligé d'en passer par là...
Et si je me passais du usfAcc pour flasher mes CodeBarre. Penses que l'évènement Change de la Feuille va également bloquer les évènements du usfSaisie ?
Il faut que j'essaie. !
A+
Bingo ! Ça fonctionne avec la saisie directe sur feuille !
Mais c'est quand même une histoire de fou...
A+
Bon finalement cette histoire de "ne termine pas la procédure" et ne libère pas l'évènement Change" ne tient pas la route :
En effet à partir de ce usfAcc il y a 2 manières d'entrer dans le usfSaisie : soit en entrant un nouveau CodeBarre dans la zone de Texte soit en cliquant sur l'étiquette SaisieCode qui génère un CodeBarre aléatoire lequel s'inscrit également dans le TextBox :
C'est donc la même procédure Change qui s'applique (et la même procédure de lancement de usfSaisie) mais dans le cas d'un CodeBarre aléatoire la classe fonctionne correctement que l'on rentre en Modification ou en mode Ajout...
Il faut donc chercher ailleurs la cause du dysfonctionnement. Ce n'est pas dans le ShowSaisie ça ne peut donc provenir que du UserForm_Activate du usfSaisie et interprétation du Tag "0" : il faut donc que je revoie toute la partie qui se trouve après le "On Error GoTo GESTERRNEWREC"
A+
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bon finalement cette histoire de "ne termine pas la procédure" et ne libère pas l'évènement Change" ne tient pas la route :
Oui et Non. Car après vérification, la seule vraie différence entre les 2 manières d'entrée est que l'événement "TB1_Change" du usfAcc n'est pas déclenché de la même manière : dans le premier cas par une saisie dans TB1, dans le second via la procédure Label2_Click.
Effectivement dans le second cas, l'événement "Change" n'est pas bloqué. De toute façon, tous les autres événements de usfSaisie fonctionnent.
Cela dit, dans le premier cas, l'événement TextBox_Change de l'usfSaisie continue de fonctionner s'il est déclenché à partir d'une procédure comme on peut le constater dans le déroulement de UserForm_Activate.
Je comprend bien que l'évènement Change peut éventuellement se comporter différemment selon la manière dont il est provoqué : On a déjà vu cela dans d'autres situations. Cependant cette affirmation ne tient que par cette constatation : Ce que je fais ne marche pas !
Il faut donc que j'en ai le cœur net donc que je bétonne le point faible de mon programme : La partie qui se trouve après le "On Error GoTo GESTERRNEWREC"
De toute façon je l'ai pondu un peu à l'arrache, je suis convaincu que je peux améliorer la logique du process qui est un peu capillotracté actuellement.
Si je n'ai pas un résultat plus probant j'abandonnerai cette idée de saisie sur usf, mais ça m'agace quand même bien... (car cet usf à vocation à être l'interface principale du programme : Les autres feuilles sont censées être inconnues de l'utilisateur lambda)
A+
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Pour terminer, une autre proposition sans Application.OnTime :
Option Explicit
Dim tb1_ok As Boolean
Private Sub Label2_Click()
Dim i
Randomize
i = Int(([rBD].Rows.Count - 2) * Rnd + 1)
Me.tb1 = [rCodeB].Cells(i, 1) 'provisoire
Application.StatusBar = i
End Sub
Private Sub TB1_Change()
Dim i%
If tb1_ok Then
i = Split(RetR(Me.tb1))(0)
If i < [rBD].Rows.Count Then '<= ??
Me.Hide
On Error GoTo GESTERR
' CBEN = CLng(Me.TB1) ' ???????????????,
ShowSaisie CLng(Me.tb1)
Else ' New CodeB
Me.Hide
CBEN = CLng(Me.tb1)
ShowSaisie
End If
Unload Me
End If
Exit Sub
GESTERR:
MsgBox "Erreur non gérée !"
End Sub
Private Sub TB1_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim code As String
If Len(Me.tb1) = 9 Then
code = Me.tb1: Me.tb1 = Empty: tb1_ok = True: Me.tb1 = code
End If
End SubMerci.
Je met cette question en attente quelques jours car je vais avoir d'autres priorité à gérer cette semaine....
En fait les vacances approchant rapidement toussa va devenir un peu problématique.
Mais j'avais déjà prévenu l'interressé que ça risquait fort d'être pour la rentrée prochaine !
A+