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 :

[Tkinter] Button, lambda et boucle : effet indesirable


Sujet :

Tkinter Python

  1. #1
    Membre habitué Avatar de KINENVEU
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    184
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 184
    Points : 131
    Points
    131
    Par défaut [Tkinter] Button, lambda et boucle : effet indesirable
    Bonjour,

    je n'arrive pas a avoir le comportement que je veux avec un "callback" de bouton.

    voici l'exemple:
    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
    import Tkinter as tk
     
    root = tk.Tk()
     
    def callback(txt):
      print "--> callback: %s"%txt
     
    aList = ["A", "B"]
    for txt in aList:
      button = tk.Button(root, text=txt)
      button["command"] = lambda:callback(txt)
      button.config(width=30, height=10)
      button.pack()
     
    root.mainloop()
    lorsque j'appuie sur un bouton (A ou B), j'obtiens le meme resultat :
    or biensur, je voudrais que ce soit la lettre du bouton.

    Comment faire pour que la fonction lambda ne soit pas liee a la variable temporaire "txt", mais a la valeur (a l'instance pour les cas plus complexes) de "txt" au moment de la creation de la fonction lambda ?

    Quelqu'un pourrait-il m'eclairer ?

    merci.

  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
    Bonjour,

    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
    #!/usr/bin/env python
    # encoding: utf-8
    #
    #
    import Tkinter as tk
     
    root = tk.Tk()
     
    def callback(txt):
        print "--> callback: %s"%txt
     
    aList = ["A", "B"]
    for txt in aList:
        button = tk.Button(root, text=txt)
        button["command"] = lambda t=txt:callback(t)
        button.config(width=30, height=10)
        button.pack()
     
    root.mainloop()
    La fonction lambda est stocké à la création du Widget. Dans votre cas lorsque l'event appelle callback(txt) le for (utilisé à la création des Widgets) est fini et txt a pour valeur... La dernière.
    Vous devez donc donner à lambda la valeur de txt au moment ou vous donnez votre fonction à command.

    @+

  3. #3
    Membre expérimenté
    Profil pro
    Développeur en systèmes embarqués retraité
    Inscrit en
    Mars 2006
    Messages
    952
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2006
    Messages : 952
    Points : 1 351
    Points
    1 351
    Par défaut
    Bonjour,

    Citation Envoyé par PauseKawa Voir le message
    lambda est stocké à la création du Widget.
    Ne serait-ce pas plutôt au moment de l'affection de la fonction lambda à l'attribut 'command'?

    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
    #!/usr/bin/env python
    # encoding: utf-8
    #
    #
    import Tkinter as tk
     
    root = tk.Tk()
     
    def callback(txt):
        print "--> callback: %s"%txt
     
    aList = ["A", "B"]
    buttons = []
    for txt in aList:
        buttons.append(tk.Button(root, text=txt, command=lambda t=txt:callback(t), width=30, height=10))
        buttons[-1].grid()
    for index, button in enumerate(buttons):  
        button["command"] = lambda text="new text %u"%(index + 1) :callback(text)
     
    root.mainloop()
    A+

    Pfeuh

  4. #4
    Membre habitué Avatar de KINENVEU
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    184
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 184
    Points : 131
    Points
    131
    Par défaut
    Merci "PauseKawa",

    c'est exactement la syntaxe que je cherchais.

  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
    Bonsoir,

    Citation Envoyé par pfeuh Voir le message
    Bonjour,
    Ne serait-ce pas plutôt au moment de l'affection de la fonction lambda à l'attribut 'command'?
    Exact pfeuh, c'est bien au moment du
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    button["command"] = lambda t=txt:callback(t)
    Par 'création du Widget' je voulais parler de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        button = tk.Button(root, text=txt)
        button["command"] = lambda t=txt:callback(t)
        button.config(width=30, height=10)
        button.pack()
    Mais il est juste qu'il est nécessaire d’être précis dans les réponses.
    Merci pour la rectification

    @+

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    Salut,
    Autre construction possible sans "lambda":
    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
    #!/usr/bin/env python
    # encoding: utf-8
    #
    #
    import Tkinter as tk
     
    root = tk.Tk()
    #
    #def callback(txt):
    #    print "--> callback: %s"%txt
     
    def callback(text):
        def inner():  #sans text=text parce que text est readonly.
            print "--> callback: %s" % text
        return inner
     
    aList = ["A", "B"]
     
    for txt in aList:
        button = tk.Button(root, text=txt)
    #    button["command"] = lambda t=txt:callback(t)
        button["command"] = callback(txt)
        button.config(width=30, height=10)
        button.pack()
     
    root.mainloop()
    Il y a déjà une discussion sur ce sujet au post

    lambda est parfois déroutant. C'est bien de connaître d'autres formes de fonctions "objets" - par abus de langage, celles dont on gèle d'une façon ou d'une autre les paramètres d'appel.
    C'est un "objet" puisque la chose a un "état".

    Plus verbeux, faire un objet "fonction"!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class callback(object):
        def __init__(self, text):
            self.text = text
        def __call__(self):
            print "--> callback: %s" % self.text
    - 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,

    Et nous en revenons aux sources:
    command est là pour stocker une fonction.
    lambda étant une fonction réduite à une simple expression, son utilité est incontournable pour le command du Widget Tkinter.Button.
    Cela se complique lorsque la 'fonction' devient plus complexe.

    Le tout est de maîtriser les expressions lambda.
    Un exemple sans 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
    19
    20
    21
    #!/usr/bin/env python
    # encoding: utf-8
    #
    #
    try:
        import Tkinter as tk
    except:
        import tkinter as tk
    import sys
     
    root = tk.Tk()
     
    for txt in ["A", "B"]:
        button = tk.Button(root, text=txt)
        button["command"] = lambda t=txt: (sys.stdout.write("--> callback: %s"%t),
                                           sys.stdout.write("\n"),
                                           sys.stdout.flush())
        button.config(width=30, height=10)
        button.pack()
     
    root.mainloop()
    Testez lambda sans passer par Tkinter KINENVEU, c'est puissant

    @+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 05/03/2016, 14h01
  2. Réponses: 13
    Dernier message: 03/03/2015, 12h52
  3. Tkinter.Button : passer et récupérer des valeurs
    Par Loïc B. dans le forum Tkinter
    Réponses: 4
    Dernier message: 20/11/2008, 21h48
  4. Tkinter: Button sur Image
    Par xEndLe dans le forum Tkinter
    Réponses: 1
    Dernier message: 04/04/2007, 20h39
  5. [Tkinter] Button connecté, avec ou sans paramètres??
    Par Sunsawe dans le forum Tkinter
    Réponses: 3
    Dernier message: 12/03/2006, 12h55

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