--------- EDITION : --------------
Attention, contrairement à ce que je croyais initialement, le problème n'a rien à voir avec les fonctions imbriquées.
------------------------------------
Bonjour à tous,
je suis confronté à un problème pour lequel je n'ai pas trouvé d'éléments de réponse dans la doc de tkinter et sur les forums.
Il s'agit d'un problème tout bête de binding à l'intérieur de fonctions imbriquées. Le problème vient peut-être d'une erreur grossière de ma part, mais je n'arrive pas à voir laquelle.
Voici un exemple du problème rencontré :
Normalement, ce code devrait faire la chose suivante : quand on clique-gauche dans le vide, un nouveau sommet est créé ; si on clique-gauche sur un sommet existant, une ligne noire est tracée entre le sommet et le curseur de la souris jusqu'à ce qu'on clique sur un autre sommet. Si on clique dans le vide, l'arête en cours de construction est effacé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
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 #!/usr/bin/env python3 from tkinter import * class Dessin(Canvas) : "Permet de tracer des points rouges et de les relier par des traits noirs" def __init__(self, boss) : Canvas.__init__(self, boss, width = 650, height = 250, bg = "white") self.bind("<Button-1>", self.ajouter_sommet) def ajouter_sommet(self, event) : print("ajouter_sommet") (x, y) = (event.x, event.y) ref = self.create_oval(x - 10, y - 10, x + 10, y + 10, fill = "red") self.addtag_withtag("sommet", ref) self.tag_bind(ref, "<Button-1>", self.ajouter_arete) def ajouter_arete(self, event) : print("ajouter_arete") (x_ini, y_ini) = (event.x, event.y) self.ligne = self.create_line(x_ini, y_ini, x_ini, y_ini, width = 3) def actualiser(event) : print("actualiser") self.delete(self.ligne) self.ligne = self.create_line(x_ini, y_ini, event.x, event.y, width = 3) def annuler(event) : print("annuler") self.delete(self.ligne) self.unbind("<Motion>") self.bind("<Button-1>", self.ajouter_sommet) self.tag_bind("sommet", "<Button-1>", self.ajouter_arete) def ajouter(event) : print("ajouter") self.unbind("<Motion>") self.bind("<Button-1>", self.ajouter_sommet) self.tag_bind("sommet", "<Button-1>", self.ajouter_arete) self.bind("<Motion>", actualiser) self.bind("<Button-1>", annuler) self.tag_bind("sommet", "<Button-1>", ajouter) # --- Test de la classe --- if __name__ == '__main__' : test = Tk() Dessin(test).pack() test.mainloop()
J'ai choisi de définir des fonctions à l'intérieur de la fonction ajouter_arete car je trouve ça plus élégant, notamment car ça permet de faire passer un certain nombre d'arguments en variables libres des fonctions internes [ici, il y en a peu, mais dans mon vrai code il y en a un peu plus] et car ça permet d'avoir une unité cohérente (la fonction ajouter_arete) sans avoir tout un tas de micro fonctions qui se baladent autour
Le problème rencontré est le suivant :
lorsque la fonction ajouter_arete est appelé par bind en réponse à <Button-1>, la fonction annuler l'est également.
Par exemple, lorsque je fais tourner le programme, j'obtiens :
Ici, les deux sommets sont créés sans encombre, mais lorsque je clique sur l'un des deux, en apparence, "rien ne se passe" - On voit en fait que ceci est dû au fait que la fonction annuler a été appelée immédiatement après ajouter_arete.
Peut-être que c'est dû au fait que lorsqu'une fonction est appelée via bind, le corps de la fonction se comporte comme si l'évènement l'ayant appelée était toujours actif ? (ça me semble bizarre mais ça expliquerait tout).
Comment remédier à ce problème ? Quelqu'un possède-t-il de la documentation sur la façon dont les évènements sont gérés ? Par exemple s'ils étaient mis dans une pile, il suffirait d'utiliser une fonction de type "flush" pour résoudre le problème...
Je débute en Python (mais pas tout à fait en programmation)
Merci d'avance !
Partager