Partage
  • Partager sur Facebook
  • Partager sur Twitter

Variable.set() et conditions

    2 août 2023 à 3:32:50

    Bonjour,

    J'ai un code dans lequel j'attends que la variable Va change avec wait_variable. Je voudrais qu'elle puisse changer de deux façon: soit si je clique sur le bouton "Valider" (cette partie là fonctionne) soit lorsque le timer se termine.

    Voici mon code :

    Va = IntVar()
    ...
        Frame33 = Frame(FrameNumeration, borderwidth=0, relief=None, bg = 'white')
        Frame33.pack(side=TOP, padx=100, pady=10, anchor = E)
        Frame3 = Frame(FrameNumeration, borderwidth=0, relief=None, bg = 'white')
        Frame3.pack(side=BOTTOM, padx=100, pady=10)
        bouton = Button(Frame3 , text = "Valider", font = ("New Roman",25) , fg = 'white', bg = 'black', command = lambda: click(Va))
        bouton.pack(side = BOTTOM)
        if Entrainement != 'non-timé':
            texte_timer = Label(Frame33,text = "",font = ( "New Roman" , 40 ), fg = 'red', bg = 'white')
            texte_timer.pack(side = RIGHT)
            Timer(Frame33,5,texte_timer)
            Va.set(1)
        
        FrameNumeration.wait_variable(Va)

    J'ai aussi essayé de remplacer Va.set(1) par click(Va) sans succès.

    def click(nom):
        nom.set(1)

    Le timer fonctionne et si je print() quelque chose après, ou juste après Va.set(1) ça fonctionne, mais le wait_variable n'est pas déclenché.

    Sauriez-vous pourquoi ?

    Je voudrais aussi que le timer soit ignoré si on clique sur le bouton "Valider".

    Merci Beaucoup!

    -
    Edité par HélèneRousseau1 2 août 2023 à 3:42:09

    • Partager sur Facebook
    • Partager sur Twitter
      2 août 2023 à 12:24:21

      Si la wait_variable n'est pas dans un callback (une fonction appelée par tkinter suite à un évènement), je ne vois pas trop comment çà pourrait fonctionner. En tout cas, vous ne montrez pas assez de code pour comprendre ce qu'il se passe. Pareil côté Timer: on ne sait pas d'où il sort (after existe pour ça côté tkinter).

      Le plus simple serait d'écrire un petit exemple de code qui traduise le comportement attendu puis d'intégrer cela dans votre application. Et si vous avez des difficultés à mettre au point le petit exemple, ça permettrait de poster un code complet qui permet de reproduire ce que vous constatez.

      Sur un petit exemple comme:

      import tkinter as tk
      
      root = tk.Tk()
      variable = tk.IntVar(value=0)
      tk.Button(root, text='add one', 
               command=lambda: variable.set(variable.get()+1)
               ).pack()
      
      label = tk.Label(root, text=0)
      label.pack()
      for _ in range(3):
          label.wait_variable(variable)
          label['text'] = variable.get()
      print('done')
      

      ça fonctionne très bien... 

      -
      Edité par mps 2 août 2023 à 13:24:51

      • Partager sur Facebook
      • Partager sur Twitter
        3 août 2023 à 1:14:12

        Si je simplifie ce que je veux faire il s'agit d'avoir une cellule dans lequel on peut entrer du texte, je souhaite que le code attende que l'on ait cliquer sur le bouton valider pour lire le contenu de la cellule. En revanche, je veux mettre un temps limite au bout duquel le contenu de la cellule est lue, quand bien même le bouton valider n'a pas été cliqué.

        Voici le code de Timer:

        def Timer(Frame,duree,texte_timer):
            count = 0
            while duree>=0:
                time.sleep(0.1)
                count = count+1
                if count%10 == 0:        
                    texte_timer['text'] = str(duree)+"s"
                    duree = duree -1
                Frame.update()

        Et j'imagine que le code devrait ressembler a quelque chose du genre sans timer:

        Va = VarInt()
        
        saisie = Entry(Frame, width=50, bg='white', font = ( "New Roman" , 25 ))
        saisie.pack()
        
        bouton = Button(Frame , text = "Valider", font = ("New Roman",25) , fg = 'white', bg = 'black', command = lambda: click(Va))
        bouton.pack(side = BOTTOM)
        
        Frame.wait_variable(Va)
        
        reponse = saisie.get()



         Ce que je ne vois pas comment faire c'est comment ajouter un timer qui une fois terminé permette de remplir la condition wait_variable, mais que si on clique sur le bouton valider auparavant alors le timer soit ignoré. Je met ici ce que j'avais naïvement pensé faire:

        Va = VarInt()
        
        saisie = Entry(Frame, width=50, bg='white', font = ( "New Roman" , 25 ))
        saisie.pack()
        
        bouton = Button(Frame , text = "Valider", font = ("New Roman",25) , fg = 'white', bg = 'black', command = lambda: click(Va))
        bouton.pack(side = BOTTOM)
        
        if Entrainement == 'timé':
        
           texte_timer = Label(Frame,text = "",font = ( "New Roman" , 40 ), fg = 'red', bg = 'white')
           texte_timer.pack(side = RIGHT)
           Timer(Frame,5,texte_timer)
           Va.set(1)
        
        Frame.wait_variable(Va)
        
        reponse = saisie.get()




        De ce que j'ai compris ça en fonctionne pas car 1. Va est changé avant d'arriver à la commande Frame.wait_variable(Va) et donc le changement n'est pas détecté , et 2. le code attends de toute façon la fin du timer avant de passer à la suite même en cliquant sur le bouton valider.
        Cependant je ne vois pas comment procéder.

        Merci beaucoup

        Simplifier le code m'a permis de trouver une solution, ce n'est peut être pas le plus élégant mais ça semble fonctionner:

        J'ai modifier Timer:

        def Timer(Frame,duree,texte_timer, var):
            count = 0
            while duree>=0:
                check = var.get()
                if check == 0:
                    time.sleep(0.1)
                    count = count+1
                    if count%10 == 0:        
                        texte_timer['text'] = str(duree)+"s"
                        duree = duree -1
                    Frame.update()
                else:
                    duree = -1

        et le code :

        Va = VarInt()
         
        saisie = Entry(Frame, width=50, bg='white', font = ( "New Roman" , 25 ))
        saisie.pack()
         
        bouton = Button(Frame , text = "Valider", font = ("New Roman",25) , fg = 'white', bg = 'black', command = lambda: click(Va))
        bouton.pack(side = BOTTOM)
         
        if Entrainement == 'timé':
         
           texte_timer = Label(Frame,text = "",font = ( "New Roman" , 40 ), fg = 'red', bg = 'white')
           texte_timer.pack(side = RIGHT)
           Timer(Frame,5,texte_timer, Va)
        
        else:
         
           Frame.wait_variable(Va)
         
        reponse = saisie.get()


        -
        Edité par HélèneRousseau1 3 août 2023 à 1:29:42

        • Partager sur Facebook
        • Partager sur Twitter
          3 août 2023 à 12:09:01

          Je suis content pour vous.

          Néanmoins, vous codez avec ce que vous croyez savoir plutôt qu'apprendre à penser avec tkinter. Regardez votre Timer: il fonctionne mais after est déjà là pour çà qu'est ce que votre mouture fait de plus?

          Récupérer le contenu d'une Entry avec timeout peut se réaliser avec:

          import tkinter as tk
          
          root = tk.Tk()
          
          def read_with_timeout(master, delay=0):
              frame = tk.Frame(master, )
              entry = tk.Entry(frame)
              entry.pack()
              tk.Button(frame, text='confirm', command=frame.quit).pack()
              frame.pack()
              if delay:
                 frame.after(delay, frame.quit)
              frame.mainloop()
              return entry.get()
          
          s = read_with_timeout(root, 5000)
          print(s)
          

          Et des exemples similaires se trouvent sur Internet. Bien sûr, ce genre de code n'est peut être pas prêt à l'emploi: il faut comprendre les mécanismes utilisés avant de pouvoir l'adapter... et si vous ne faites pas l'effort de comprendre comment faire avec tkinter, ben, vous n'y arriverez pas.

          Un code est "vivant"! Si on arrive à coder un truc qui marche de façon satisfaisante aujourd'hui, demain on aura peut être envie de le faire évoluer. Et pour ça le modifier sans tout casser! Ce qui suppose pouvoir le relire facilement... Au plus, il sera concis au plus ce sera facile sinon il faudra en ré-écrire de grosses parties. Pire, ce faisant vous imaginez maîtriser et tendrez à recopier vos solutions dans d'autres constructions qui seront aussi bancales.



          • Partager sur Facebook
          • Partager sur Twitter
            17 août 2023 à 18:17:19

            Je pense que la réflexion initiale était mauvaise: tu veux en fait traiter la valeur soit au clic sur le bouton, soit au bout de 5 secondes si timer.

            Pour moi, la logique serait d'appeler la fonction de traitement (click ici) au click ou après le délai de 5 secondes.

            Dans cette fonction, il faudrait donc commencer par annuler le after (au cas où on y entre par le clic normal), récupérer la valeur de l'entry et la traiter.

            un exemple:

            import tkinter as tk
            
            root=tk.Tk()
            
            Va=tk.IntVar()
            id_after=0
            e1=tk.Entry(root,textvariable=Va)
            e1.pack()
            
            Entertainement='timé'
            
            def click():
                global id_after,Va
                root.after_cancel(id_after) #on annule le after initié
                l1["text"]=Va.get()
            
            b1=tk.Button(root,text="Valider",command=click)
            b1.pack()
            
            l1=tk.Label(root,text="réponse")
            l1.pack()
            
            if Entertainement=="timé":
                id_after=root.after(5000,click) # après 5s (5000ms), on exécute click
            
            root.mainloop()
            



            • Partager sur Facebook
            • Partager sur Twitter
              17 août 2023 à 18:36:32

              umfred a écrit:

              Je pense que la réflexion initiale était mauvaise: tu veux en fait traiter la valeur soit au clic sur le bouton, soit au bout de 5 secondes si timer.

              La saisie d'une Entry doit toujours être validée par ailleurs, histoire que l'utilisateur confirme que ce qu'il a saisi est correct: d'où le Button. Je ne vois pas ce que ça change si on force l'utilisateur à faire cela en un temps déterminé: il ne peut plus aller à la machine à café.

              Par contre, on peut dire qu'il manque un cancel dans mon code et que cela peut poser problème de recevoir un quit n'importe quand:

              import tkinter as tk
               
              root = tk.Tk()
               
              def read_with_timeout(master, delay=0):
              
                  ident = None
              
                  frame = tk.Frame(master, )
                  entry = tk.Entry(frame)
                  entry.pack()
                  tk.Button(frame, text='confirm', command=frame.quit).pack()
                  frame.pack()
                  if delay:
                     ident = frame.after(delay, frame.quit)
                  frame.mainloop()
                  if ident:
                     frame.after_cancel(ident)
                  return entry.get()
               
              s = read_with_timeout(root, 5000)
              print(s)
              

              mais la logique reste la même, on a juste corrigé un bug qui n'existe pas encore.

              -
              Edité par mps 17 août 2023 à 18:41:56

              • Partager sur Facebook
              • Partager sur Twitter

              Variable.set() et conditions

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown