Bonjour,
Suite à plusieurs discussions sur la manipulation du statut de l'activation des évènements, calculs, affichage, protection des feuilles ect ... qui est source de conflit,
je me suis penché sur le problème.
Historiquement, des problèmes peuvent apparaitre lors de l'appel de sous-fonction qui manipulent ces status, dont la fonction appelante n'a pas conscience (et elle n'a pas à s'en préoccuper).
Par exemple:
La fonction Bar rétablit l'affichage, en conséquence, les instructions suivantes mettant à jour l'affichage provoquent d'horribles clignotements à l'écran, ce qui dégrade l'expérience utilisateur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 Public Sub Foo() Application.ScreenUpdating = False '// code qui manipule l'affichage Bar '// code qui manipule l'affichage Application.ScreenUpdating = True End Sub Private Sub Bar() Application.ScreenUpdating = False '// code qui manipule l'affichage Application.ScreenUpdating = True End Sub
Une première solution peut consister à ne désactiver l'affichage que dans la fonction de plus haut niveau:
Mais, cela implique que la fonction appelante aie une idée précise du comportement des fonctions appelées,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 Public Sub Foo() Application.ScreenUpdating = False '// code qui manipule l'affichage Bar '// code qui manipule l'affichage Application.ScreenUpdating = True End Sub Private Sub Bar() '// code qui manipule l'affichage End Sub
et que les fonctions appelées assument que la fonction appelante a pris ses dispositions.
Ce qui en contradiction avec la Loi de Demeter.
Une seconde solution peut consister à mémoriser l'état de l'affichage en début de fonction, et le restituer en fin de fonction:
C'est correcte, mais c'est une approche défensive de la programmation, d'une part lourdingue, d'autre part qui détourne le développeur de sa tâche première: Produire une fonction avec le comportement escompté.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 Public Sub Foo() Application.ScreenUpdating = False '// code qui manipule l'affichage Bar '// code qui manipule l'affichage Application.ScreenUpdating = True End Sub Private Sub Bar() Dim ScreenUpdating As Boolean ScreenUpdating = Application.ScreenUpdating Application.ScreenUpdating = False '// code qui manipule l'affichage Application.ScreenUpdating = ScreenUpdating End Sub
N'y a t'il pas un moyen d'automatiser la sauvegarde / restauration de ces status ?
Je pense que oui, via une classe au final fort simple, qu'il suffira d'instancier (et oublier sa présence):
Cette classe nécéssite un module Factory pour être instanciée:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 '// Class ApplicationStateHolder Option Explicit '// référence vers l'application Private mApp As Excel.Application '// Status que l'on désire mémoriser Private mEnableEvents As Boolean Private mScreenUpdating As Boolean Private mCalculation As Boolean '// Pseudo-constructeur '// Memorisation des status Friend Sub Create(ByRef App As Excel.Application) Set mApp = App mEnableEvents = mApp.EnableEvents mScreenUpdating = mApp.ScreenUpdating mCalculation = mApp.Calculation End Sub '// Destructeur '// Restitution des status Private Sub Class_Terminate() mApp.enableevent = mEnableEvents mApp.sceenupdating = mScreenUpdating End Sub
Demo:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 '// Module: Factory Option Explicit Public Function CreateApplicationStateHolder(ByRef App As Excel.Application) As ApplicationStateHolder Dim State As ApplicationStateHolder Set State = New ApplicationStateHolder State.Create App Set CreateApplicationStateHolder = State End Function
Lorsqu'une fonction se termine, l'instance State est détruite, ce qui entraine la restauration des status sauvegardés en début de fonction.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 Public Sub Foo() Dim State As ApplicationStateHolder Set State = Factory.CreateApplicationStateHolder(Application) Application.ScreenUpdating = False '// code qui manipule l'affichage Bar '// code qui manipule l'affichage End Sub Private Sub Bar() Dim State As ApplicationStateHolder Set State = Factory.CreateApplicationStateHolder(Application) Application.ScreenUpdating = False '// code qui manipule l'affichage End Sub
Les fonctions Foo et Bar peuvent maintenant manipuler l'affichage pour leurs besoins propre, sans avoir à se soucier de ce qu'on fait leurs prédécesseurs, ni ce que feront leurs successeurs,
elles sont plus facile à lire et à comprendre.
Des classes reposant sur le même principe, concernant les feuilles (protection) ou autre objet sont envisageable.
Partager