TextBox, Module de classe, Addition de temps Heures Minutes
Bonjour le forum,
Je sollicite vos lumières afin de pouvoir faire avancer mon projet. Il s'agit de additionner des temps (TextBox 1, 2 et 3) et afficher le résultat en TextBox4. J'ai déjà fait une partie du code (module de classe, userform, mise en forme, etc.) mais manque l'essentiel: faire l'addition. Vous trouverez, en pièce jointe, un extrait de mon projet ainsi que des explications complémentaires.
Je remercie d'avance toute éventuelle aide fournie. Cordialement Jorge.
Je n'ai pas traité le problème avec une classe.
Etant donné que le format de saisie était imposé à 00:00 c'est 01:33 qu'il faudra entrer au lieu de 1:33.
Proposition :
Bonjour Optimix, le forum,
Merci pour ta proposition. Note sur le format : dans mon extrait, la saisie doit se faire sous format "00:00". Ensuite, après traitement, la saisie "18:30" s'affiche "18:30", la saisie "01:15" s'affiche "1:15" et la saisie "00:35" s'affiche ":35".
Concernant ta proposition, le problème rencontré est que la saisie dans les TextBox 1, 2 et 3 est bloquée. Pourrais-tu me fournir des explications complémentaires? Merci d'avance.
Je ne suis pas sûr d'avoir tout compris. Essayez ceci :
Ce que j'essaye de vous dire est que les TextBox 1, 2 et 3 sont bloqués. Impossible d'effectuer une quelconque saisie (chiffres ou caractères). Même situation avec la version 3 de votre proposition.
C'est vraiment bizarre. Malgré certaines manipulations, les TextBox continuent à être bloqués.
Quelqu'un d'autre pourrait essayer et nous dire s'il rencontre le même problème?
J'avais une dernière question : que faut-il afficher pour 00:22 (uniquement des minutes) ?
L'affichage idéal serait "00:22: mais ça peut être ":22" ou "22".
Sans module de classe, j'avais ce fichier qui fonctionne pas mal.
En attendant un visiteur, la v4 avec :22 pour 00:22.
Obligé de couper pour la journée.
Bonne nouvelle.
En remplaçant la ligne de code du TextBox1_KeyDown (et pareil pour les TextBox 2 et 3) :
If KeyCode < 96 Or KeyCode > 105 Then KeyCode = 0
par
If KeyCode < 47 Or KeyCode > 58 Then KeyCode = 0
j'ai pu saisir des chiffres et vérifier la pertinence de l'addition en TextBox4. Il reste, toutefois, le problème du tabulateur bloqué qui empêche d'avancer dans les 3 premiers textbox.
L'idée avec un module de classe était de simplifier la procédure gourmande en code pour ces seules quatre TextBox. En effet, l'extrait presenté ici n'est qu'un petit bout de mon projet principal qui est déjà assez généreux en code. Le code presenté dans mon post de 13:03, sans module de classe, réalise un travail similaire à celui que vous avez développé ici.
Apparemment, la création d'un module de classe, est trop compliqué. Je ne désespère pas de trouver une solution et continuerais à rechercher dans le net.
Dans tous les cas, je vous remercie pour le temps dédie et votre persévérance.
Bonjour,
Voici ci-joint votre projet entièrement revu en utilisant une classe customisée comme vous l'aviez demandé. Cependant vous verrez qu'au niveau de l'architecture c'est plus complexe (a priori, car a posteriori l'utilisation est plus aisée).
Pour info :
Malgré certaines manipulations, les TextBox continuent à être bloqués.
En bloquant les keycode vous bloquez le TAB qui est le numéro 9. J'ai utilisé Change qui permet une plus grande liberté à l'utilisateur. On retire les mauvais caractères après la saisie tout en autorisant l'utilisation complète du clavier (touches de flèches, tabulation, majuscules+num etc).
Le calcul du total se fait en temps réel grâce aux events. Les ":" sont ajoutés automatiquement pour vous faciliter la saisie ("1245" devient "12:45" automatiquement).
Pour aller plus loin : il faudrait créer une seconde classe contenant une collection de notre classe customisée. Cela permettrait une utilisation plus simple si vous utilisez des "groupes" de textbox dans différents userforms de votre projet, car vous auriez moins de code à écrire dans l'Userform. Cependant par soucis de simplification et de meilleure compréhension pour vous je ne l'ai pas fait (c'est un nouveau niveau d'abstraction).
Si vous avez des retours à faire je vous en prie. Bonne journée.
Re, pour terminer sur le sujet si ça intéresse les curieux, je joins ci-après une solution (plus complexe) qui utilise une collection de notre module de classe customisé.
Le problème le plus ennuyeux est le suivant : quand on utilise une classe customisée (que j'appellerai "Wrapper" ici) on perd l'accès à certains évènements de la TextBox, notamment TextBox.Exit. C'est très ennuyant car c'est le moment idéal pour effectuer la vérification de la saisie.
Le contournement que j'ai donné dans mon précédent post était d'utiliser une boucle Do/While, mais ce n'est pas très optimal car ça bloque toute autre exécution VBA, et c'est assez lourd niveau CPU pour vraiment rien.
L'idéal serait de travailler avec l'event Exit dans le wrapper, cependant ce n'est pas possible... Afin d'alléger un peu le code précédent (surtout dans la partie userform) j'ai ajouté un module de timer (une horloge) qui va checker toutes les 250 ms si quelque chose s'est passé (en l'occurrence, le changement de focus d'un Textbox à l'autre dans l'userform). Ce module utilise des appels à l'API Windows afin d'être plus optimisé, mais essentiellement c'est le même job que la boucle do/while. Il permet également de gérer plusieurs userforms simultanés, et surtout ne bloque pas l'exécution VBA entre les ticks.
Donc pour résumer, le code suit cette structure :
Classes et rôles :
- TBHoraire : logique d’un TextBox (format live, parse, validate).
- TBHItem : “pont d’événements” (écoute un TBHoraire et relaie à la collection).
- CollTBH : collection d’items + watcher (détecte changement de focus, lance Validate au bon moment) + affiche un événement unique OnAnyChanged pour l’UF.
- ModTimer : timer partagé (WinAPI) qui pulse (verif toutes les 250 ms) les groupes enregistrés (TBHTimer_Register / TBHTimer_Unregister).
Pour l'intégration avec l'userform, ca se passe en 3 temps :
- Initialize : créer une CollTBH, y ajouter les TextBox=>TBHoraire puis initialiser le total.
- Activate : Horaires.StartWatcher Me → enregistrement auprès du timer global (commence à boucler la verification).
- QueryClose (cloture UF) : Horaires.StopWatcher → désenregistrement, fin des vérifications pour la collection CollTBH liée à cet userform.
Et durant l'utilisation, voici ce qu'il se passe :
écriture dans TextBox -> TBHoraire.tb_Change -> formatage + RaiseEvent OnChange -> TBHoraires_OnAnyChanged (UF) -> UpdateTotal (recalcul du total)
clic ailleurs -> (250 ms) Tick -> TBHoraires.WatcherTick voit le focus changer -> Validate sur la textbox à peine quittée.
Bonjour Saboh12617, le forum,
Vous avez réalisé un travail magnifique. Les deux exemples s'acquitent haut la main des consignes imposées. Toutefois, votre travail est d'un niveau qui dépasse largement mes maigres connaissances et je pense qu'il me faudra un certain temps pour l'étudier sérieusement.
Vous avez était impecable comme d'habitude et je vous remercie infiniment. Cordiales salutations.
Je vous en prie, content d'avoir pu répondre à la question. J'ai bien conscience que c'est beaucoup plus complexe, je pense que dans votre cas mon second message (deuxième solution) n'a pas d'intérêt à être étudié.
La solution de Optimix est certainement beaucoup plus facile à comprendre. Comme je le disais le petit soucis qui vous empêchait d'utiliser TAB (et selon moi beaucoup d'autres touches [flèches, suppression, etc.]) c'est que la verification de KeyUp est beaucoup trop restrictive :
If KeyCode < 96 Or KeyCode > 105 Then KeyCode = 0
Cela bloque tout ce qui est hors pavé numérique, il faudrait plutôt inverser la condition et ajouter les cas spéciaux. On peut utiliser Select Case pour s'y retrouver facilement :
Select Case KeyCode
Case 8, 9, 13, 37 To 40, 46, 96 To 105 ' la virgule = "ou"
' Autoriser ces touches
Case Else
KeyCode = 0 ' Bloquer les autres
End SelectAvec
- Tab (KeyCode = 9)
- Backspace (KeyCode = 8)
- Flèches directionnelles (KeyCodes = 37 à 40)
- Suppr (Delete) (KeyCode = 46)
- Entrée (KeyCode = 13)
- Et bien sûr les chiffres du pavé numérique (96 à 105)
Voilà. Pour info je viens de poster un petit tutoriel (mais il en existe d'autres très bien) sur comment créer une application avec des UserForm robustes en VBA. Dans le cas d'un petit minuteur comme le votre c'est sans doute exagéré mais si votre appli devient plus importante, c'est une approche robuste.
Bonne journée, n'oubliez pas de clôturer le fil en sélectionnant les réponses qui ont pu vous aider.
Bonjour saboh12617, le forum,
Bon, je voulais finir ce fil sur une note positive. En effet, après quelques heures d'insomnie, j'ai trouvé une solution plus harmonieuse pour un petit projet come le mien. Dans l'extrait de projet mis en pièce jointe j'ai réussi à mettre le traitement complet des heures et minutes (addition) dans le Module de classe. Je crois avoir tout testé mais s'il y a des pépins, je vous serais reconnaissant de me les communiquer. Encore un grand merci à Saboh. Cordiales salutations.
Bonjour georg,
C'est un très bon début, vous avez commencé à vous approprier les modules de classes et l'intérêt qu'ils offrent (regrouper en un lieu unique la fonctionnalité de divers objets identiques) + comment les connecter aux boutons de votre UserForm.
Si le fonctionnement vous convient, je ne vois pas d'erreurs "grossières" dans votre code.
Personnellement j'ai noté que si l'on essayait d'entrer des heures du type "1:30" ça ne fonctionnait pas, il faut taper "01:30". Mais bon, c'est du détail, et Optimix et moi vous avons déjà donné une solution si jamais vous vouliez intégrer ce type de fonctionnalité.
Je tenais à vous féliciter pour votre résilience. Le fait que vous ayez pris le temps de reprendre le projet de zéro sans copier/coller une des solutions proposées montre une motivation rare et je suis sur qu'elle vous portera loin. La solution finale est peu être un peu moins "élaborée", mais vous avez appris beaucoup plus en faisant comme cela et vous maitrisez votre projet.
Bonne journée et au plaisir d'échanger de nouveau sur le forum
Bonjour,
Personnellement j'ai noté que si l'on essayait d'entrer des heures du type "1:30" ça ne fonctionnait pas, il faut taper "01:30". Mais bon, c'est du détail, et Optimix et moi vous avons déjà donné une solution si jamais vous vouliez intégrer ce type de fonctionnalité.
Dans mon code, il n'est pas nécessaire de taper le séparateur ":". Il se place automatiquement en troisième position. Je l'ai conçu ainsi afin d'éviter la fastidieuse manipulation de devoir taper Maj pour introduire les deux points (oui, je sais, je suis un flémard). La saisie "130" affiche donc le résultat non souhaité de "13:0". Et il est impossible de taper "1:30" car le Keypress bloque la saisie de ":" en deuxième position.
Pour obtenir le résultat de "1:30" j'ai dû adapter et rajouter le code KeyUp d'Optimix au Module de classe. Et cela fonctionne mais il n'empeche qu'il faut toujours taper les quatre chiffres "0130". Ce mode de faire ne me dérange pas du tout et le résultat me convient parfaitement.
Je tenais à vous féliciter pour votre résilience. Le fait que vous ayez pris le temps de reprendre le projet de zéro sans copier/coller une des solutions proposées montre une motivation rare et je suis sur qu'elle vous portera loin. La solution finale est peu être un peu moins "élaborée", mais vous avez appris beaucoup plus en faisant comme cela et vous maitrisez votre projet.
Venant de vous, je me sent honoré. Vos commentaires bienveillants et judicieux m'on permis de réfléchir autrement. Et merci également à Optimix pour sa participation, ses propositions et sa ténacité. Je garde ses fichiers pour des éventuelles adaptations futures.
Meilleures salutations à vous deux.
