IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

modifier une stringVar sans appeler sa trace


Sujet :

Tkinter Python

  1. #1
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut modifier une stringVar sans appeler sa trace
    Bonjour,

    Je dispose d'une stringVar à laquelle j'ai associée un callback
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    s= stringVar()
    s.set('valeur initiale')
    s.trace("w",fun)
    Puis-je modifier la valeur de s sans déclencher l'appel du callback fun ?

    Merci d'avance

  2. #2
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    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 ?

    @+

  3. #3
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut Merci
    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.

  4. #4
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    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.

    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
    #!/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())
    Sortie
    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
    Le set dans les fonctions ne passe donc pas par le callback puisque celui ci n'existe plus.

    Comprendre par visibilité ici root.wcb_v1(2) pour le callback et celle de fun1 et 2.
    A vous de voir suivant votre code.

    @+

  5. #5
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Oups

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    print('Valeur de V1 ' + V1.get())
    print('Valeur de V2 ' + V2.get())

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Citation Envoyé par VV33D Voir le message
    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).
    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.

    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
    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())
    Ceci dit, comme on peut associer plusieurs callbacks à une même StringVar,
    la vraie question est côté "utilité de synchroniser" deux StringVar plutôt que d'en utiliser une seule.
    - W

  7. #7
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonjour,

    C'est effectivement bien plus simple avec _name.
    Mais pourquoi tester nval ?

    Sinon pour en finir avec trace_vdelete
    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
    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])
    Bizarrement cela fonctionne aussi en asynchrone (tester avec des threads sur V1/V2).
    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.

    @+

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Citation Envoyé par PauseKawa Voir le message
    C'est effectivement bien plus simple avec _name. Mais pourquoi tester nval ?
    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.

    La solution de wiztricks reste la meilleure bien sur.
    C'est gentil.
    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.

  9. #9
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonsoir,

    Citation Envoyé par wiztricks Voir le message
    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.
    A comprendre la validation d'une Entry ?
    Pas mal...

    @+

  10. #10
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Re,

    Citation Envoyé par VV33D Voir le message
    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
    Mais...
    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.

    @+

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Citation Envoyé par PauseKawa Voir le message
    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

  12. #12
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Merci beaucoup pour ces réponses et toutes ces remarques pertinentes.

    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.
    C'est pas faux ca ! Je vais aller dans cette voie, ca me semble plus naturel.

    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)

Discussions similaires

  1. Reflection : Créer une instance sans appeler le constructeur
    Par cboun94 dans le forum Framework .NET
    Réponses: 8
    Dernier message: 17/12/2007, 17h26
  2. Réponses: 3
    Dernier message: 31/07/2007, 21h18
  3. instancier une variable sans appeller de methode?
    Par debutant_linux dans le forum Ruby on Rails
    Réponses: 4
    Dernier message: 05/07/2007, 11h31
  4. modifier une propriété sans connaitre son nom
    Par cyberchand dans le forum C#
    Réponses: 2
    Dernier message: 17/04/2007, 16h17
  5. Modifier une page sans la recharger...
    Par Ylias dans le forum Général JavaScript
    Réponses: 12
    Dernier message: 10/05/2006, 11h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo