19 - Interface et variables globales
Nous avons vu dans l'activité précédente qu'il existe deux types de variables.
- les variables locales sont les variables déclarées dans une fonction.. Elles ne peuvent être lues et modifiées qu'à l'intérieur de leur fonction puisqu'elles n'existent que le temps de son exécution.
- les variables globales sont les variables qui sont créées directement dans le corps du programme.
En application directe, nous réaliserons aujourd'hui une interface graphique événementielle avec tkinter, utilisant fonctions et variables globales.
En effet, le problème est, qu'avec l'interface Tkinter, on ne peut donner que des noms de fonctions (sans pouvoir fournir de paramètres donc) lorsqu'on veut créer une action sur un clic ou autre.
|
|
L'une des façons de régler cela : les variables globales. Mais souvenez-vous : ce n'est pas bien.
Logiciel nécessaire pour l'activité : Python 3
Evaluation ✎ : 07 à faire valider en classe (à part la notion d'interface, de capteurs et d'actionneurs, aucune connaissance ici ne fait pas partie du programme officiel, mais savoir créer une (petite) interface graphique est plutôt agréable)
Documents de cours : open document ou pdf
ATTENTION : utiliser les variables globales n'est pas vraiment une bonne pratique. Ici, c'est juste pour contourner la façon dont Tkinter demande de gérer les événements.
On pourrait d'ailleurs gérer cela proprement mais vous n'avez pas encore les connaissances permettant de le faire.
1 - Application aux interfaces graphiques
Interface graphique ou textuelle
Lorsqu'on crée un programme, on aime bien qu'il puisse interagir avec l'utilisateur.
Deux mondes coexistent donc :
- D'un côté, le monde physique dans lequel l'utilisateur peut agir sur l'ordinateur et voir l'écran par exemple.
- De l'autre côté, le programme qui tourne à l'intérieur de l'ordinateur
Pourtant, une interaction entre les deux mondes est possible. Ce point d'interaction se nomme
- une interface graphique si on peut s'y déplacer avec la souris
- une interface textuelle si l'interactivité se limite à l'utilisation du clavier (on parle alors de console ou de terminal)

Les interactions se font dans les deux sens :
- L'utilisateur peut transmettre des informations au programme en passant par l'interface
- Le programme peut transmettre des informations à l'utilisateur en passant par l'interface.
Cette interface est capable de faire le lien entre le monde extérieur et le code informatique interne.
L'interface graphique est donc composée d'un ensemble de programmes préexistants au votre.
Pour cela, elle a besoin de communiquer avec les composants matériels qui permettent à l'utilisateur de transmettre ou recevoir des informations de l'utilisateur.
Capteurs et actionneurs

Définitions
- Un capteur est un composant capable de transmettre une information issue du monde physique en signal électronique ou informatique.
- Un actionneur est un composant capable de provoquer à partir d'un signal électronique une action réelle dans le monde physique
Grandeur physique | >>> | CAPTEUR | >>> | |
Valeur numérique |
Grandeur physique | <<< | ACTIONNEUR | <<< | |
Valeur numérique |
01° Classer les trois composants visibles (écran, clavier, souris) en les mettant
- soit dans la catégorie des capteurs,
- soit dans la catégorie des actionneurs.
...CORRECTION...
La souris et le clavier sont des capteurs puisqu'on envoie des informations vers le système informatique.
L'écran est un actionneur : le système informatique parvient bien à modifier l'apparence de l'écran physique.
On notera qu'un écran TACTILE est à la fois un capteur et un actionneur.
A quoi peuvent servir les variables globales dans le cadre d'une application graphique ? A imposer une charte graphique commune à plusieurs éléments puisqu'on peut lire les variables globales depuis l'intérieur des fonctions.
Voici un exemple de programme d'interface graphique qui :
- Importe les fonctionnalités du module d'interface graphique tkinter en le renommant tk.
- Définit six couleurs via des constantes :
- Crée l'interface graphique et stocke sa référence dans une variable nommée application. Elle apparaît en or foncé sur le site pour montrer qu'il s'agit d'une variable liée à l'interface graphique.
- Crée et positionne avec place() neufs widgets de type Label-text. wL1C1 veut dire que ce widget doit être sur la première ligne (L1) de la première Colonne (C1).
- Stocke en ligne 65 dans le tableau tableau_widgets toutes les références des widgets
- Indique à l'aide de la méthode bind() de surveiller les événements "Clic avec le bouton gauche" (clic sur le bouton 1) sur les différents widgets : lors d'un cloc, il faudra lancer la fonction événementielle modifier().
- Lance l'application en fonctionnement événementiel : à partir de cette ligne, le programme ne fait que surveiller les événements et réagir en conséquence. On sort du mode programmation séquentielle pour rentrer en programmation événementielle en boucle infinie.
1
2
3 |
|
6
7
8
9
10
11
12 |
|
27
28
29
30
31
32
33
34 |
|
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 |
|
65 |
|
67
68
69
70
71
72
73
74
75
76
77 |
|
Notez bien qu'on ne transmet que le nom modifier de la fonction modifier(). Pas de parenthèse. L'explication est dans la partie suivante.
79
80 |
|
Et on aura alors ceci :
02° Mettre le programme fourni ci-dessous en mémoire et lancer. Cliquer sur les widgets pour voir le résultat.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 |
|
Questions :
- En cliquant sur les carrés, parvient-on bien à modifier leurs couleurs ?
- Le seul paramètre de la fonction événementielle modifier() correspond-t-il aux constantes de couleurs ?
- La fonction événementielle modifier() parvient-elle à lire les variables globales du programme principal ?
...CORRECTION...
On parvient bien à modifier les couleurs des carrés et pourtant on ne transmet pas les constantes via les paramètres.
La fonction événementielle modifier() ne possède qu'un paramètre nommé event (voir ligne 17).
17 |
|
On peut en déduire que depuis une fonction, on peut effectivement lire le contenu des variables globales.
2 - Evénement Click
03° Nous avons vu que
- la méthode pour placer les widgets se nomme place(),
- la méthode pour configurer/modifier l'un des attributs d'un widget se nomme configure(),
- la méthode pour lire l'un des attributs d'un widget se nomme cget(),
Question : comment se nomme la méthode qui permet de générer une liaison entre un événement et le déclenchement d'une fonction ?
...CORRECTION...
Il s'agit de la méthode bind() qui veut dire lier en anglais.
On notera deux choses importantes :
- Lors de la création de l'événement, on ne donne que le nom d'une fonction (modifier ici donc), sans pouvoir lui transmettre d'arguments.
- Cette fonction modifier() n'est néanmoins pas une fonction normale : il s'agit d'une fonction événementielle, elle doit avoir un paramètre qui sera rempli automatiquement par l'application graphique tkinter avec les informations enregistrées lors de la détection de l'événement (position de la souris, la référence du widget on vient de cliquer...) C'est un peu bizarre : on va devoir déclarer un paramètre (souvent nommé event ou juste e) qui sera transmis automatiquement à Python par l'interface Tkinter.
2 |
|
04° Etudier la fonction modifier() proposée. Répondre ensuite aux questions.
15
16
17
18
19
20
21
22
23
24 |
|
- L17 : Comment se nomme le paramètre recevant les informations de l'événement dans cette fonction ?
- L19 : Que doit-on taper pour récupérer le widget qui est à l'origine de l'événement ?
- L20 : La méthode cget() permet de récupérer l'un des attributs d'un widget. Ici, son fond coloré. Que contient initialement l'attribut bg du widget cliqué (pensez à aller voir la création des widgets sur les lignes 36+) ?
- L22 : Que réalise cette instruction ?
- Dans quel cas va-t-on réaliser la ligne 24 ?
...CORRECTION...
- Comment se nomme le paramètre recevant les informations de l'événement dans cette fonction ?
- Que doit-on taper pour récupérer le widget qui est à l'origine de l'événement ?
- La méthode cget() permet de récupérer l'un des attributs d'un widget. Ici, son fond coloré. Que contient initialement l'attribut bg du widget cliqué ?
- Que réaliser alors la ligne 22 ?
- Dans quel cas va-t-on réaliser la ligne 24 ?
Le paramètre se nomme event.
Il faut taper event.widget
Initialement, le fond coloré avait été réglé avec COULEUR_0.
22 |
|
En Français, cela veut dire d'activer la méthode configure() sur le widget dont on a stocké la référence dans widget_clic et de changer son attribut fond coloré : on y place la couleur COULEUR_1.
Cette fois, on active la méthode configure() sur le widget dont on a stocké la référence dans widget_clic et on change son attribut fond coloré : on y place la couleur suivante COULEUR_2.
✎ 05 - Faire vérifier° Compléter la fonction modifier() pour pouvoir avoir un cycle de couleur 0 vers 1, 1 vers 2, 2 vers 3, 3 vers 4 et 4 vers 1 lorsqu'on clique sur les widgets.
3 - Conclusion : lire le tableau
Imaginons qu'on veuille modifier la couleur de tous les carrés lorsqu'on clique sur l'un d'entre eux avec un clic-droit.
Nous avions enregistré le tableau des 9 widgets, vous vous souvenez ?
65 |
|
Cela veut dire qu'avec :
- tableau_widgets[0] on récupére la référence du widget wL1C1.
- tableau_widgets[8] on récupére la référence du widget wL3C3.
- tableau_widgets[9] on déclenche une erreur puisque l'indice 9 n'existe pas dans un tableau de 9 éléments. Les indices vont de 0 à 8 uniquement.
Comme tableau_widgets est une variable globale, nous allons pouvoir la lire depuis la fonction et déplacer un à un tous les carrés à l'aide de leurs références qui se trouvent dans ce tableau global.
06° Exécuter ce programme : avec un clic-droit sur les carrés, on parvient à les déplacer vers la droite.
Lire les modifications surlignées puis répondre à ces questions :
- Comment parvient-on à créer les surveillances des clics-droits en deux lignes uniquement ?
- Qu'aurions-nous dû taper si on n'avait pas utilisé de boucle ?
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 |
|
...CORRECTION...
On utilise une boucle POUR avec une variable de boucle i qui va prendre successivement les valeurs 0, 1, 2, 3... jusqu'à 8. Pourquoi ? Simplement car la longueur du tableau est de 9.
Nous aurions pu taper ceci si nous avions voulu nous passer de la boucle :
1
2
3
4
5
6
7
8
9 |
|
07° Regardons comment fonctionne la fonction événementielle deplacer().
- Cette fonction reçoit-elle le tableau via son paramètre ou parvient-elle à le lire car le tableau est une variable globale ?
- Dans le cas de notre programme, quelles vont être les valeurs successives prises par la variable de boucle i ?
- Que contient widget_en_cours lors du premier tour de boucle ?
- Comment se nomme la méthode permettant de récupérer la coordonnée x où est placé un widget ?
- Pourquoi le widget se déplace-t-il à droite ?
26
27
28
29
30
31
32 |
|
...CORRECTION...
- Cette fonction reçoit-elle le tableau via son paramètre ou parvient-elle à le lire car le tableau est une variable globale ?
- Dans le cas de notre programme, quelles vont être les valeurs successives prises par la variable de boucle i ?
- Que contient widget_en_cours lors du premier tour de boucle ?
- Comment se nomme la méthode permettant de récupérer la coordonnée x où est placé un widget ?
- Pourquoi le widget se déplace-t-il à droite ?
Elle ne reçoit pas cette variable. Mais, la fonction peut la lire puisque le tableau est une variable globale.
Le tableau contient 9 widgets dont les indices vont de 0 à 8.
L'indice vaut 0 au départ. Le widget est donc celui stocké à l'indice 0. C'est celui qui correspond à wL1C1
Ligne 30. On voit qu'il faut utiliser winfo_x().
Ligne 32. On voit qu'on place widget en rajoutant 10 à la coordonnée qu'on a lu avec winfo_x().
CONCLUSION
Vous connaissez maintenant la notion de variables globales dont la portée en lecture s'étend jusqu'aux fonctions.
Leur utilisation peut paraître sympathique mais les variables globales ne devront être utilisées.
Pourquoi ? Nous verrons que leur utilisation rend la correction et la vérification des fonctions bien délicates.
Dans quel cas les utiliser alors ? Dans le cadre de NSI, on peut se limiter à ces deux cas :
- Pour permettre aux fonctions événementielles d'avoir accès à des informations non liées au widget ayant déclenché l'événement (comme ici)
- Pour éviter de créer des fonctions dont la plupart des paramètres recoivent des CONSTANTES globales (comme dans votre projet console qcm, jeu ou générateur de scénario)
4 - FAQ
Et si on veut faire plus de choses avec Tkinter ?
Il existe beaucoup de documentation sur le Web.
Les informations risquent néanmoins d'être encore difficiles à comprendre pour le moment.
Sinon, vous trouverez ci-dessous un petit tuto pour faire quelques petites manipulations :
J'ai vu des programmes avec un mot-clé global. C'est quoi ?
C'est un moyen permettant à une fonction de parvenir à agir sur une variable globale, une variable définie dans le corps du programme.
Il ne faut pas l'utiliser dans le cadre d'un programme, à moins d'y être contraint.
Si vraiment vous voulez savoir comment ça fonctionne, vous pouvez lire la suite. Mais bon : vous n'aurez pas le droit de l'utiliser en NSI de toutes manières. C'est juste de la curiosité.
...CORRECTION...
Comment faire alors pour modifier une variable globale depuis une fonction ?
Voyons comment faire avec ce petit bout de cours fortement optionnel :
Rappel : comportement de Python par défaut
- une fonction peut lire une variable globale.
- une fonction ne peut pas modifier une variable globale
- l'utilisation d'une affectation (
=
) crée simplement une variable locale portant le même nom.
Nouveau : modification du comportement par défaut
- une fonction peut modifier une variable globale si on lui en donne l'autorisation :
- en utilisant le mot-clé
global
suivi du nom de la variable avant de l'affecter
- en utilisant le mot-clé
Mise en pratique immédiate :
1
2
3
4
5
6
7
8
9 | ennemi = "Darth Vador"
|
Ligne 7 : On affiche le contenu "Darth Vador"
Lignes 8 puis 4 et 5 : On permet à la fonction de modifier la variable en "Palpatine"
Ligne 9 : La variable globale contient bien "Palpatine" maintenant.
20° Lancer ce programme sur Python Tutor ou Thonny en mode DEBUG pour visualiser la modification du contenu de la variable.
21° Utiliser maintenant Thonny en mode DEBUG avec visualisation du tas (heap) pour connaitre le contenu ET l'id de la variable au cours de l'execution du programme. L'id de la variable globale a-t-elle été modifié après la ligne 5 ? Pour vous convaincre de la différence sans la ligne 4, vous pouvez la supprimer et relancer un nouveau debug.
CLIQUEZ ICI POUR VOIR LE CONTENU DES VARIABLES :
test :
ennemi :
Id 0x6E18 :
Id 0x3FC0 :
Id 0xB030 :
1
2
3
4
5
6
7
8
9 | ennemi = "Darth Vador"
|
Voilà, nous sommes parvenus à modifier une variable globale depuis une fonction. Attention, n'oubliez pas que la variable change d'identifiant associé, comme à chaque fois qu'on utilise une affectation =
.
Spécificités des portées en fonction des variables
La portée des variables globales et locales, ainsi que la façon dont on peut les modifier est variable en fonction du langage de programmation. Il s'agit d'une des premières choses qu'il faut regarder et comprendre lorsqu'on s'attaque à un nouveau langage. Pour vous, c'est fait avec Python maintenant.
Note finale : Limitez l'utilisation des variables globales !
La modification des variables globales avec global doit rester marginale dans vos programmes. Il est en effet difficile de maintenir fonctionnel un code qui comporte plusieurs variables modifiées par plusieurs fonctions créées par des personnes différentes.
Si vous devez utilisez des variables globales (même en lecture simple), respectez au moins ces trois points :
- Placer les clairement en début de code dans la partie adéquate de façon à clairement les mettre en évidence.
- Placer des commentaires pour expliquer à quoi elles servent
- Donner leur des noms suffisamment rares pour que quelqu'un ne les écrase dans une fonction par une variable locale portant le même nom : si l'une de vos variables globales se nomme
x
, il ne faudra pas vous plaindre si l'une des personnes de votre équipe utilise aussi ce nom dans l'une de ses fonctions !
Sachez que nous verrons plus tard des outils nous permettant de nous passer des modifications de variables globales depuis les fonctions. Vous pouvez donc les utiliser pour l'instant, mais gardez à l'esprit qu'il s'agit plutôt d'une mauvaise pratique.
Activité publiée le 01 11 2020
Dernière modification : 30 01 2022
Auteur : ows. h.