Bonjour,
Je dispose d'une stringVar à laquelle j'ai associée un callback
Puis-je modifier la valeur de s sans déclencher l'appel du callback fun ?Code:
1
2
3
4 s= stringVar() s.set('valeur initiale') s.trace("w",fun)
Merci d'avance
Version imprimable
Bonjour,
Je dispose d'une stringVar à laquelle j'ai associée un callback
Puis-je modifier la valeur de s sans déclencher l'appel du callback fun ?Code:
1
2
3
4 s= stringVar() s.set('valeur initiale') s.trace("w",fun)
Merci d'avance
Bonsoir,
Oui, vous avez une sacré panoplie pour cela (trace_vdelete, globalgetvar, globalsetvar, tout est possible).
Par contre comme je n'en comprend pas l'utilité : Pourquoi ne pas faire une exeption dans le callback ?
@+
Bonsoir Pause Kawa,
Merci je vais aller voir ces fonctions.
Le cas qui m'intéresse est le suivant: j'ai deux variables liées par une relation bijective V2= f(V1). L'utilisateur peut saisir soit V1 soit V2, et je veux alors mettre à jour l'autre variable automatiquement (c'est pourquoi j'utilise des stringVar avec .trace() sur chaque variable qui va aller affecter l'autre).
Cela déclenche donc une infinité d'appels récursifs, qu'il me semble impossible d'éviter même en touchant le code du callback.
Bonjour,
C'est donc bien de trace_vdelete que vous avez besoin.
Par contre il vas falloir faire attention à la visibilité des callbacks et du nom de la fonction de trace.
SortieCode:
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 #!/usr/bin/env python # -*- coding: UTF-8 -*- # # try: from Tkinter import * except: from tkinter import * def fun1(nom, index, mode): print('pass by fun1') print('nom: ' + nom) print('index: ' + index) print('mode: ' + mode) print('Modification de V2, soit ' + V2._name) valeur = V1.get()[0] V2.trace_vdelete('w', root.wcb_v2) V2.set('b') root.wcb_v2 = V2.trace_variable('w', fun2) def fun2(nom, index, mode): print('pass by fun2') print('nom: ' + nom) print('index: ' + index) print('mode: ' + mode) print('Modification de V1, soit ' + V1._name) valeur = V2.get() V1.trace_vdelete('w', root.wcb_v1) V1.set('b') root.wcb_v1 = V1.trace_variable('w', fun1) root = Tk() V1 = StringVar() V2 = StringVar() root.wcb_v1 = V1.trace_variable('w', fun1) root.wcb_v2 = V2.trace_variable('w', fun2) V1.set('aaaaa') print('Valeur de V2 ' + V2.get()) print('------------------------------------') V2.set('c') print('Valeur de V1 ' + V2.get()) print('Valeur de V2 ' + V2.get())
Le set dans les fonctions ne passe donc pas par le callback puisque celui ci n'existe plus.Citation:
pass by fun1
nom: PY_VAR0
index:
mode: w
Modification de V2, soit PY_VAR1
Valeur de V2 b
------------------------------------
pass by fun2
nom: PY_VAR1
index:
mode: w
Modification de V1, soit PY_VAR0
Valeur de V1 c
Valeur de V2 c
Comprendre par visibilité ici root.wcb_v1(2) pour le callback et celle de fun1 et 2.
A vous de voir suivant votre code.
@+
Oups
Code:
1
2 print('Valeur de V1 ' + V1.get()) print('Valeur de V2 ' + V2.get())
Dans ce cas 'simple', on évite les "boucles" en posant que la cible ne doit être mise à jour que si elle est différente de la source. Ce qui demande:
- la liste des StringVar qu'on souhaite synchroniser,
- le callback qui fait le boulot de mise à jour.
Ceci dit, comme on peut associer plusieurs callbacks à une même StringVar,Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 root = Tk() V1 = StringVar() V2 = StringVar() root.VX = V1, V2 # need to store list of bound vars def callback(name, *dummy): print 'callback', name nval = root.tk.getvar(name) for v in root.VX: if v._name == name or v.get() == nval: continue v.set(nval) V1.trace_variable('w', callback) V2.trace_variable('w', callback) V1.set('aaa') print('Valeur de V1 ' + V1.get()) print('------------------------------------') V2.set('c') print('Valeur de V1 ' + V1.get()) print('Valeur de V2 ' + V2.get())
la vraie question est côté "utilité de synchroniser" deux StringVar plutôt que d'en utiliser une seule.
- W
Bonjour,
C'est effectivement bien plus simple avec _name.
Mais pourquoi tester nval ?
Sinon pour en finir avec trace_vdelete
Bizarrement cela fonctionne aussi en asynchrone (tester avec des threads sur V1/V2).Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 def fun(name, *dummy): nval = root.tk.getvar(name) for v in root.VX: if v._name == name: continue for elem in v.trace_vinfo(): # elem[0] mode, elem[1] nom du callback pour tcl (cbname) if elem[0] == 'w': # On supprime le callback sans supprimer son nom pour l'interpreteur tcl root.tk.call("trace", "vdelete", v, 'w', elem[1]) # f bidon # Dans le tuple root.VX root.VX[0] est V1 et root.VX[1] V2 if v._name == root.VX[0]._name: # V1 v.set(v.get()[:4] + nval) else: # V2 v.set(nval[4]) # On refais le callback sur le cbname connu de tcl root.tk.call("trace", "variable", v, 'w', elem[1])
Ce n'est sans doute pas très utile ici mais cela montre comment désactiver momentanément (et en gardant l'information pour ce qui est de la fonction) un callback.
La solution de wiztricks reste la meilleure bien sur.
@+
Tester que la cible est à jour permet de ne pas désarmer les callbacks.
C'est la différence avec ta solution qui les désarme et les réarme pour éviter le flooding des appels induits par la modification.
C'est gentil.Citation:
La solution de wiztricks reste la meilleure bien sur.
Je ne vois toujours pas l'intérêt de synchroniser deux StringVar plutôt que d'utiliser le même et dans ce cas, pas besoin de callbacks pour gérer les mises à jour...
- W
PS: le callback étant appelé à toute modification (insertion ou suppression d'un caractère), il sera plutôt à utiliser pour valider une saisie en temps réel.
Et propager la mise à jour "après"..., la saisie terminée.
Bonsoir,
A comprendre la validation d'une Entry ?
Pas mal...
@+
Par exemple, mais c'est "limite" d'autant qu'une Entry (ou autre widgets) permettent d'avoir des events définis sur des caractères tapés qui vont bien aussi. Ca fait des contorsions assez "limites".
Personnellement, j'utilise plutot les StringVar comme "delegate" lorsque la valeur d'un même champ (nom, adresse,...) doit être affiché par/dans plusieurs widgets. Mais j'utilise peu la trace car, les actions suite à une mise à jour sont déclenchées "plus haut" via le widget.
- W
Merci beaucoup pour ces réponses et toutes ces remarques pertinentes.
C'est pas faux ca ! Je vais aller dans cette voie, ca me semble plus naturel.Citation:
Si c'est dans un Widget (Entry, etc) que l'utilisateur mets à jour on a même pas besoin de validation ou autre StringVar.
C'est au Widget de mettre à jour V1 et V2.
Cela dit si je change mon interface (remplacant l'edit par un autre widget), il faut que j'en tienne compte ; alors qu'une stringVar avec trace() semble mieux découpler le problème (et se situe dans l'espace des solutions, pas dans celui de l'interface)