Re: Appels de procédures et portée de variables |
Titre du sujet : Re: Appels de procédures et portée de variables par myDearFriend! le 13/01/2008 23:57:48 Re dss, Citation : dss a dit : Tout d'abord, merci de ta remarque car l'objectif du présent site est effectivement avant tout d'apporter les explications utiles et nécessaires à chacun pour une meilleure compréhension et une bonne maitrise de son propre projet. Le tout n'est pas de fournir un code tout prêt à un demandeur, mais de s'assurer qu'il saura le comprendre, voire l'adapter à ses besoins futures. C'est en tout cas dans cette intention que j'ai créé cet endroit... Citation : dss a dit : Prenons un exemple simple : Dans le module de code d'une feuille de calcul, j'ai cette procédure :
Private Sub Worksheet_Change(ByVal Target As Range)
En réalité, ce code est une anomalie et est inccorrect. Pourquoi ? Si tu le testes, tu vas vite t'apercevoir que ce code rentre dans une boucle sans fin ! (pour interrompre, appuyer sur Echap) Car une fois la cellule modifiée par l'utilisateur (qui rentre une valeur numérique), la ligne "Target.Value = Target.Value + 1" va elle-même déclencher une nouvelle fois l'évènement Change(), qui va lui aussi déclencher une nouvelle fois ce même code, etc... Pour contourner ce genre de situation, il y a plusieurs façon de faire. [list=1] [*]Utilisation de Application.EnableEvents = False / True qui permet de désactiver les évènements de VBA : On pourrait l'employer comme ceci :
Private Sub Worksheet_Change(ByVal Target As Range)
Mais je déconseille fortement d'utiliser cette méthode ! Si par un malheureux hasard, ton code plante entre les 2 instructions, ton classeur perdra sa gestion d'évènements VBA et plus aucune procédure évènementielle ne se déclenchera automatiquement pendant que l'utilisateur continuera de travailler... bonjour les dégâts ! Dans l'exemple ci-dessus, ça sera le cas si l'utilisateur saisit une valeur non numérique en A1 : le code va planter sur la ligne "Target.Value = Target.Value + 1" pour incompatibilité de type et la propriété EnableEvents ne retrouvera jamais sa valeur True... [*]Utilisation d'une variable de portée Module : On peut aussi contourner le problème comme suit (tu trouveras le plus souvent cette solution dans les forums de discussions) :
Option Explicit
[list] [*]Une variable boolean (valeur True ou False) est mise à True (ici elle se nomme "EnCours") juste avant l'instruction fautive qui entraine la boucle non souhaitée. [*]En tête de procédure, un contrôle est fait sur la valeur de cette variable : si True, alors... passe ton chemin ! (Exit Sub) [*]Juste après l'instruction fautive, on redonne une valeur False à cette variable de contrôle. Pour que ça puisse fonctionner, on a déclaré cette variable en tête de module afin qu'elle puisse conserver toujours sa valeur entre les différents appels de l'évènement (ça ne marcherait pas si on la déclarait à l'intérieur même de la procédure). [/list] [*]Utilisation d'une variable déclarée Static : Il s'agit exactement du même principe que pour la variable déclarée en tête de module. Le mot clé Static (pour une variable déclarée à l'intérieur d'une procédure) permet toutefois à cette variable de conserver sa valeur même si on quitte la dite procédure et bien que celle-ci n'ait pas une portée Module.
Option Explicit
[/list] Alors variable Static ou variable de portée Module ? Pour moi, la clé du problème se situe non seulement au niveau de la durée de vie de la variable mais aussi, et surtout, au niveau de la portée que l'on veut donner à la dite variable. Une variable Public ou Private déclarée au niveau Module trouve son utilité uniquement si elle doit être partagée entre plusieurs procédures. Par exemple, si je décidais de chronométrer la durée d'ouverture d'un classeur, je déclarerais une variable vTemps en tête de module de l'objet ThisWorkbook, je lui affecterais l'heure courante dans l'évènement Open() et je réutiliserais sa valeur dans l'évènement BeforeClose() du même objet pour calculer la durée de la session. Dans le cas cité plus haut (et également dans ton projet), il s'agit uniquement de permettre à la variable de conserver sa valeur, une seule procédure est concernée ici et la valeur n'est pas partagée entre plusieurs évènements. La portée étant donc restreinte, une simple variable déclarée Static à l'intérieur même de cette procédure, suffit à répondre à la seule contrainte de durée de vie. Personnellement, je privilégie l'utilisation des variables Static quand j'en ai la possibilité. Je les trouve beaucoup plus faciles à gérer. Pour moi, plus la portée de la variable est restreinte, et plus il devient facile d'en maîtriser le contenu. On réduit d'autant les risques de changement de valeur inattendu à un autre endroit dans le code... On peut ainsi déclarer des variables Static avec le même nom dans plusieurs procédures différentes. Chacune de ses variables reste donc indépendante et conserve sa propre valeur dans sa propre procédure. Moi, je trouve ça pratique... Par ailleurs, même si je suis dans l'incapacité de le prouver, j'ai dans l'idée qu'une variable Static consomme moins de ressources qu'une variable déclarée en tête de module. Cordialement, |
Forums