Garder une variable en mémoire entre plusieurs procédures
Bonjour,
Je reviens vous voir après avoir séché plusieurs heures, malgré tests et recherches sur le forum
Je cherche à conserver une variable incrémentée(compteur*) dans une procédure (proc1) située dans un module "moduleext". Celle-ci fonctionnera lorsqu'elle sera appelée par une procédure principale (Main) située dans un module différent.
Note : j'ai trois fichiers : un principal, un avec les fonctions et un avec les procédures. J'ai fait ça dans le but de garder le module main lisible, ayant beaucoup de procédures et fonctions.
Le problème que j'ai est que la variable se réinitialise à chaque appel de la procédure.
J'ai trouvé sur le web qu'en sauvegardant la valeur dans une cellule d'une feuille ça fonctionne et je suis d'accord. Je voudrai éviter d'écrire dans le classeur cette variable.
Mon code (très simplifié, j'espère qu'il reste compréhensible) est pour le main :
Public Points As Integer
Public ligne As Integer
Public compteur1 As Integer
Public compteur2 As Integer
Sub Main()
ligne = 1
For i = 1 To 10
Points = Empty
'les deux fonctions suivantes retournent un certain nombre de Points en fonction des données d'entrées analysés ligne par ligne dans une feuille séparée. Les fonctions sont situées dans un module différent appelé Fonction
Fonction.Position(ligne)
Fonction.Poids(ligne)
'la procédure suivante compare les points et compte la récurrence. cf code suivant
moduleext.proc1 ()
ligne= ligne+ 1
Next i
MsgBox compteur1 & Chr(10) & compteur2
End SubPour la procédure qui incrémente le compteur :
Sub proc1()
If Points < 100 Then
compteur1 = compteur1 + 1
ElseIf Points >= 100 And Points < 200 Then
compteur2 = compteur2 + 1
End If
End SubNaturellement, comme la variable ne se conserve pas, j'ai la boîte de dialogue qui reste vide.
Merci d'avance pour vos pistes et votre aide
Bonjour,
Peux-tu nous mettre les 3 classeurs en pièce jointe svp
(sans les feuilles ou avec des feuilles vides) juste quelques macros et surtout les déclarations auxquelles elles font appel.
A+
Bonjour,
Une variable déclarée au niveau module conserve sa valeur !
Tu n'es pas très clair dans tes explications. Tu sembles multiplier inutilement les variables comme dans Main... et tes appels de procédure incluant le nom de module laisserait entendre (si tu sais ce que tu fais) que tu as privatisé tes modules (pas malin sans justification !)
Tout ça est nébuleux...
Salut Galopin.
Cordialement.
Bonjour,
Note : j'ai trois fichiers : un principal, un avec les fonctions et un avec les procédures.
D'un classeur tu ne peux pas voir les variables d'un autre (enfin tu peux, mais c'est un peu lourd je trouve). Public est de portée classeur.
Si c'est ça ton soucis le plus simple est de passer par un nom :
'Classeur1
Sub test()
Dim varTest As Long
varTest = 7 ' initialiser la valeur avant .Names.Add
ThisWorkbook.Names.Add "test", RefersTo:=varTest, Visible:=False
End Sub
'Classeur2
Sub test()
Debug.Print Workbooks("Classeur1.xlsm").Names("test") ' retourne: "=7"
End SubEt le plus simple encore est que tu mettes tous tes modules dans le même classeur, sinon c'est se compliquer la vie.
eric
Voilà donc le fichier que j'utilise situé à la fin de ce message. J'ai supprimé beaucoup de parties qui n'avaient aucun impact, et j'ai tenté de garder "l'essentiel".
Le principe est : en appuyant sur le bouton opération, une feuille "résultat" se crée, balaye la feuille "extrait" et poste les résultats dedans.
Ce que je souhaite, c'est qu'en même temps que les résultats soient calculés, il y ait une itération qui se fasse pour compter les catégories A, B ou C obtenues en fonction du nombre de points final.
Note : le fichier est destiné à faire une série de tests, et de modifier les encadrements, les points affectés par parties d'où les nombreux liens vers les variables.
J'ai tenté de les définir au mieux sous forme de tableau, mais je suis preneur pour toute critique que j'étudierai attentivement demain
J'ai bien noté que si tout est dans le même module c'est bien plus facile et si aucun moyen relativement simple n'est trouvé c'est ce que je ferai. Cependant, ayant beaucoup de Sub et Function pour cette programmation, l'objectif premier est bien de garder une feuille compréhensible et relativement lisible dans un module "principal" qui irait chercher et exécuter les différentes sub et fonctions voulues.
J'espère avoir été le plus clair possible, je sais pertinemment que c'est un peu "Nébuleux" et je m'emploi au maximum pour essayer de comprendre et de rendre les choses simples, et essayant également de garder une logique. Ce n'est pas toujours facile
Excellente soirée
Le fichier :
Je ne retrouve pas les noms de proc. que tu citais... Pourrais-tu localiser le problème ?
Le problème que j'ai est que la variable se réinitialise à chaque appel de la procédure.
Nom de la variable ?
Nom de la procédure ?
Salut
Les procédures que je citais en message #1 ne sont pas présentes dans le fichier .xlsm posté. J'avais tapé un code pour illustrer mon propos.
Dans le fichier que j'ai envoyé, la procédure qui pose problème s'appelle classe_compteur. Elle identifie la classe (en sommant les points récoltés) et fait une itération supplémentaire sur la classe identifié à chaque tour de boucle For.
Elle se situe dans le classeur Subtest et est appelée dans le Main.
Les variables sont
compteur(0)
compteur(1)
compteur(2)
compteur(3)Elles sont déclarées dans le Main.
Mes excuses pour l'incompréhension.
J'ai bien noté que si tout est dans le même module c'est bien plus facile
Personne n'a dit ça.
Moi je te demandais si tes modules étaient dans différents classeurs.
eric
S'il s'agit de compteur, tu le vides à chaque appel de la procédure, que veux-tu qu'il contienne ? sinon le résultat du dernier appel !
En effet, j'ai mélangé deux notions que l'on peut difficilement confondre.
Donc les modules sont tous dans un seul classeur et au nombre de 3. Comme avec le fichier déposé.
MFerrand, je viens de lire ton message d'entre temps et j'ai fait la modification : en enlevant le code ça incrémente correctement .
compteur(0) = Empty
compteur(1) = Empty
compteur(2) = Empty
compteur(3) = EmptyLe fichier :
Je me sens super bête après avoir chercher tant de temps dessus, mettant des MsgBox un peu partout pour suivre la variable.. J'ai une question du coup : pour initialiser la variable (en Empty je suppose), il faut que je le fasse en dehors de la procédure. Ça doit donc obligatoirement se faire dans le Main?
BlueMountain
Oui il faut vider avant de commencer, mais une seule fois !
Pour ne pas tout perdre : avec Erase compteur tu vides ton tableau et tu t'épargnes 3 lignes.
Tu n'es pas obligé d'utiliser le nom de module dans l'appel des procédures, les modules standard sont publics.
Sauf dans le cas de dualité de nom de procédure entre deux modules.
Je me suis aussi demandé pourquoi tu mettais les arguments passés aux procédures entre parenthèses, cela correspond à forcer un passage par référence (ByRef).
Cordialement
Bonjour
J'ai indiqué le fil de discussion comme réglé.
Du coup, je vais mettre en place la commande qui vide le tableau. J'ai noté la particularité qui ne m'oblige pas à indiquer le nom de module quant j'appelle une procédure, j'avais trouvé cette commande sur un bout de programme sur internet et c'était resté.
Quant à l'utilisation des parenthèses en argument des procédures, j'avais appliqué la logique des fonctions qui placent leurs variables entre parenthèse.
En revanche, je ne comprends pas ce que signifie :
cela correspond à forcer un passage par référence (ByRef).
BlueMountain
Bonjour,
La question des parenthèses :
Appel proc. Function : x = MaFonc(arg1, arg2) , la fonction renvoie un résultat, elle est située à droite d'un signe =, les arguments doivent être entre parenthèses.
Fonction utilisée sans récupération du résultat, ex. fréquent avec MsgBox (qui est une fonction) :
MsgBox "blabla", ,"Information" , pas de parenthèses, alors que naturellement tu en mets pour poser une question et récupérer la réponse de l'utilisateur.
Appel proc. Sub : MaMacro arg1, arg2 , cas général, pas de parenthèse.
Tu lances ta proc. avec Call : Call MaMacro(arg1, arg2) , dans ce cas, parenthèses obligatoires.
Quand tu as écrit ta macro, tu l'as déclarée : Sub MaMacro(arg1 As String, arg2 As Integer)
Tu n'as pas précisé la façon dont les arguments devaient être passés, donc par défaut ils sont passés par référence. Ce qui exige que la variable que tu utilises dans ta procédure appelante soit exactement du type demandé dans ta déclaration. Si ce n'est pas le cas, VBA va te stopper avec un : "Argument ByRef incompatible".
Dans ce cas 2 solutions :
soit tu révises ta déclaration : Sub MaMacro(ByVal arg1 As String, ByVal arg2 As Integer) , et tout roule...
soit tu forces dans ton appel : MaMacro (arg1), (arg2), la mise entre parenthèse de chaque argument indique que tu forces le passage par référence.
Quand tu passes ByRef (cas par défaut) la modification éventuelle de l'argument passé se répercute sur la variable source, mais en passant par valeur (ByVal) VBA crée une copie et donc pas de répercussion en retour. Dans l'utilisation courante, les cas où tu veux absolument maintenir cet effet en retour me paraissent plutôt rares (d'où ma question).
Si tu forçais avec utilisation de Call : Call MaMacro((arg1), (arg2))
Une petite ambiguïté venait du fait que tes procédures appelées n'ayant qu'un argument, le mettre entre parenthèses constituant une manoeuvre licite ne soulevait pas de réaction de VBA. Mais avec 2 arguments les mettre entre parenthèses (sans utilisation de Call) globalement (et non chaque argument individuellement) aurait entrainé un refus immédiat de VBA (avec un "Attendu =").
Cordialement.
Bonjour
MFerrand : merci beaucoup pour toutes ces explications. En les relisant plusieurs fois, j'arrive à intégrer le principe. Pour l'instant mon code fonctionne tel quel et je dois avancer son développement. Lorsque j'aurai un peu de temps, je l'adapterai entièrement avec plus de rigueur (dans 2 semaines environ)..
Ceci étant, je te remercie encore, l'utilisation des variables est plus clair pour moi dorénavant
Cordialement,
BlueMountain