Partage
  • Partager sur Facebook
  • Partager sur Twitter

Tkinter

Lire une variable externe dans la boucle Tkinter

    9 février 2024 à 5:58:41

    Bonjour,

    Voilà des jours que je tourne en rond à la recherche de tutos qui me montreraient comment suivre une variable sur un écran d'accueil créé avec Tkinter.

    Très précisément, ma question est la suivante: j'ai réalisé une application de sous-titrage de photos et je veux maintenant l'appliquer à toutes les photos d'un répertoire donné. La structure de mon appli est donc la suivante:

    for i , photo in enumerate(listdir(rep_photos)):
        sous_titrer(photo)


    Je cherche donc comment faire figurer la variable i dans l'écran d'accueil (conçu avec Tkinter) qui doit être affiché pendant tout le déroulement du traitement des photos.

    Après maints essais, j'en suis arrivé à la conclusion qu'il faut pour cela créer deux threads un pour le programme lui-même et un pour la partie Tkinter (l'écran d'accueil). J'ai juste ?

    Merci d'avance pour toute solution ou idée ou lien que vous voudrez bien m'apporter.

    CAPLANDE

    -
    Edité par caplande 9 février 2024 à 7:37:42

    • Partager sur Facebook
    • Partager sur Twitter
      9 février 2024 à 8:40:30

      Bonjour,

      Votre question est bien plus précise sur ce forum que sur le précédent en tout cas, on sait que vous utilisez tkinter et dans quel contexte.

      Après maints essais, j'en suis arrivé à la conclusion qu'il faut pour cela créer deux threads un pour le programme lui-même et un pour la partie Tkinter (l'écran d'accueil). J'ai juste ?

      ça doit être faisable, complexe mais faisable, cependant je ne suis pas certains que se soit nécessaire.

      Pourquoi ne pas avant chaque apparition de photo, afficher la variable i dans un des widgets tkinter (un Label par ex.) ?

      Pour la mise à jour de votre variable vous pouvez utilisez StringVar qui sera configuré à chaque changement de photo.

      • Partager sur Facebook
      • Partager sur Twitter

      Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
      La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

        9 février 2024 à 9:41:59

        Merci pour votre réponse.

        Dans la question posée précédemment, je n'envisageais pas d'utiliser Tkinter, c'est en désespoir de cause que je me rabats sur ce package.

        Mais nouvelle difficulté: Afficher un écran avec Tkinter semble assez facile lorsque tous les événements sont déclenchés à partir de widgets de l'écran Tkinter (boutons, entrée de texte etc...) . Mon cas de figure est différent puisque l'événement (changement du numéro de photo) est déclenché par le changement d'une variable python extérieure à la boucle Tkinter (qui se termine par root.mainloop()).

        En résumé: Je ne sais pas comment lier l'événement et la boucle Tkinter.

        Peut-être (probablement) pourrez-vous m'aiguiller. Merci d'avance.

        NOTA: Je ne suis spécialiste de rien, je suis curieux de tout, j'aime chercher les solutions des problèmes auxquels je suis confronté, mais arrive un moment où il faut admettre son échec face à certaines difficultés (témoin la date de ma première question sur le sujet)

        CAPLANDE

        • Partager sur Facebook
        • Partager sur Twitter
          9 février 2024 à 9:48:32

          caplande a écrit:

          En résumé: Je ne sais pas comment lier l'événement et la boucle Tkinter.

          Peut-être (probablement) pourrez-vous m'aiguiller.

          StringVar ou after peuvent faire le job... reste à apprendre à les utiliser (et chercher des exemples sur Internet ou ouvrir un  tuto pour apprendre à utiliser tkinter).
          • Partager sur Facebook
          • Partager sur Twitter
            9 février 2024 à 9:56:35

            reste à apprendre à les utiliser (et chercher des exemples sur Internet ou ouvrir un  tuto pour apprendre à utiliser tkinter
            Je n'y avais pas pensé !
            • Partager sur Facebook
            • Partager sur Twitter
              9 février 2024 à 10:03:05

              Bonjour,

              "Mon cas de figure est différent puisque l'événement(changement du numéro de photo)

              est déclenché par le changement d'une variable python extérieure à la boucle Tkinter"

              Non, ce n'est pas un problème

              Il faut créer une fenêtre Tkinter

              puis y insérer un Label

              puis ajouter

              root.mainloop() à la fin

              Et dans la boucle, on peut écrire ceci:

              for i , photo in enumerate(listdir(rep_photos)):
                  sous_titrer(photo)
                  mon_label['text'] = str(i)



              • Partager sur Facebook
              • Partager sur Twitter
                9 février 2024 à 10:09:04

                Merci pour cette réponse aidante.

                J'ai utilisé la structure que vous me proposez. Avec ce modèle la boucle for s'exécute sans que la fenêtre ne s'affiche et lorsque la boucle for est complètement terminée, la fenêtre s'affiche avec l'exécution de root.mainloop()

                • Partager sur Facebook
                • Partager sur Twitter
                  9 février 2024 à 10:35:37

                  caplande a écrit:

                  reste à apprendre à les utiliser (et chercher des exemples sur Internet ou ouvrir un  tuto pour apprendre à utiliser tkinter

                  Je n'y avais pas pensé !


                  Y penser? Je vous suggère de le faire... et d'arriver à proposer un code semi fonctionnel qui montre un peu ce que vous cherchez à faire. Là c'est à nous de proposer et vous êtes juste un consommateur alors que vous êtes supposé programmer.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    9 février 2024 à 10:51:43

                    Dans la question posée précédemment, je n'envisageais pas d'utiliser Tkinter, c'est en désespoir de cause que je me rabats sur ce package.

                    Je suis curieux. Avez-vous testé les solutions sur ce forum ?

                    Pouvez-vous présenté un code minimum et testable présentant le non fonctionnement et ce que vous attendez concrètement ?

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                      9 février 2024 à 11:26:58

                      Voici ma dernière tentative utilisant à la fois Tkinter et les threads

                      import time
                      import tkinter as tk
                      from tkinter import *
                      import threading as th
                      
                      i = 0
                      variable_i = None
                      label = None
                      def actualiser_label():
                          global label
                          variable_i.set(str(i))
                          label.update()
                      
                      def construire_ecran():
                          global variable_i,label
                          # Définition d'un objet "fenêtre"
                          root = Tk()  	# nouvelle instance de Tk
                          root.title("Affichage d'une variable")
                          root.geometry("600x400")
                      
                          variable_i = StringVar(root,str(i))
                          label = Label(root, textvariable=variable_i)
                          label.pack()
                          variable_i.trace_add('write',actualiser_label) # type: ignore
                          root.mainloop()
                      
                      def pp():
                          global i
                      time.sleep(1) for i in range(1,6): time.sleep(1) print(f"i = {i}") t1 = th.Thread(target = construire_ecran) t2 = th.Thread(target = pp) t1.start() t2.start() t1.join() t2.join() print("C'est fini")

                      La valeur de i reste figée à 1. Le débogage montre que variable_i.trace_add est inopérant

                      • Partager sur Facebook
                      • Partager sur Twitter
                        9 février 2024 à 11:34:45

                        En fait vous ne répondez pas aux questions qu'on vous pose, ne prêtez pas attentions aux remarques, et appliquez encore moins les propositions qui vous sont faîtes.
                        • Partager sur Facebook
                        • Partager sur Twitter

                        Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                        La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                          9 février 2024 à 13:05:48

                          caplande a écrit:

                          Voici ma dernière tentative utilisant à la fois Tkinter et les threads

                          Si vous aviez pris le temps d'apprendre à programmer avec tkinter, vous sauriez qu'on évite d'utiliser des threads quand ce n'est pas utile.

                          Puis pour mettre à jour un Label toutes les secondes, savoir écrire un code comme:

                          import tkinter as tk
                          
                          label = tk.Label()
                          label.pack()
                          
                          def update_label(count=0):
                              if count == 10:
                                 return
                              label['text'] = count
                              label.after(1000, update_label, count+1)
                          
                          update_label()
                          tk.mainloop()
                          
                          • Partager sur Facebook
                          • Partager sur Twitter
                            9 février 2024 à 14:02:13

                            "Merci pour cette réponse aidante.
                            J'ai utilisé la structure que vous me proposez. Avec ce modèle la boucle
                            for s'exécute sans que la fenêtre ne s'affiche et lorsque la boucle
                            for est complètement terminée, la fenêtre s'affiche avec l'exécution de
                            root.mainloop()"
                            Je dois dire que j'avais testé avec cet exemple simple qui fonctionne très bien:
                            from tkinter import *
                            
                            WIDTH, HEIGHT = 400, 200
                            
                            main_win = Tk()
                            main_win.title('Test')
                            main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100')
                            
                            L1 = Label(main_win, text = '>')
                            L1.place(x=100, y=100)
                            
                            for k in range(10): L1['text'] = str(k)
                            
                            main_win.mainloop()
                            OK ca se déroule très vite: il faudrait faire une fonction comme celle proposée
                            ci-dessus par MPS

                            -
                            Edité par Phil_1857 9 février 2024 à 14:10:30

                            • Partager sur Facebook
                            • Partager sur Twitter
                              9 février 2024 à 14:36:09

                              mps a écrit:

                              Puis pour mettre à jour un Label toutes les secondes, savoir écrire un code comme:

                              Sans oublier d'instancier Tk() :-°

                              • Partager sur Facebook
                              • Partager sur Twitter
                                9 février 2024 à 17:05:18

                                Garkam a écrit:

                                mps a écrit:

                                Puis pour mettre à jour un Label toutes les secondes, savoir écrire un code comme:

                                Sans oublier d'instancier Tk() :-°

                                Si vous aviez testé mon code, vous auriez constaté qu'il fonctionne sans instancier Tk. Elle se fait par défaut dès la création du premier widget.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  9 février 2024 à 17:45:31

                                  A l'attention de PHIL1857,

                                   Je ne crois pas que votre script (recopié ci-dessous) fonctionne. En effet, le mainloop() ne s'exécute qu'après que l'itération sur la boucle for est entièrement exécutée ce qui veut dire que l'écran affiché ne montre que la dernière valeur.

                                   
                                  WIDTH, HEIGHT = 400, 200
                                   
                                  main_win = Tk()
                                  main_win.title('Test')
                                  main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100')
                                   
                                  L1 = Label(main_win, text = '>')
                                  L1.place(x=100, y=100)
                                   
                                  for k in range(10): L1['text'] = str(k)
                                   
                                  main_win.mainloop()
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    9 février 2024 à 18:24:54

                                    En effet, le mainloop() ne s'exécute qu'après que l'itération sur la boucle for est entièrement exécutée ce qui veut dire que l'écran affiché ne montre que la dernière valeur.

                                    ça n'a rien à voir avec la position du mainloop, c'est simplement que les textes du label s'enquillent les uns derrière les autres à une vitesse de l'ordre d'un temps non visible par l'homme (microseconde ou milliseconde). Il est donc normal de voir la dernières valeur enregistrée par L1['text'].

                                    Mais il manque pas grand chose à ce code, juste revoir celui de @mps qui rajoute une tempo de 1s.

                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                                    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                                      9 février 2024 à 18:41:02

                                      caplande a écrit:

                                      En effet, le mainloop() ne s'exécute qu'après que l'itération sur la boucle for est entièrement exécutée ce qui veut dire que l'écran affiché ne montre que la dernière valeur.

                                      Ce n'est pas faux... et si on veut faire fonctionner ce code, on écrirait plutôt:

                                      import tkinter as tk
                                      from time import sleep
                                      
                                      label = tk.Label()
                                      label.pack()
                                      
                                      for i in range(10):
                                          label['text'] = i
                                          label.update()
                                          sleep(1.0)
                                      
                                      print('done')
                                      

                                      sans mainloop et avec sleep...

                                      C'est de la programmation "avancée". Il faut comprendre les conditions normales d'utilisation de ce genre de construction pour pouvoir les utiliser dans de vrais programmes sans foutre une grouille pas possible si on ne les respecte pas.

                                      -
                                      Edité par mps 9 février 2024 à 18:46:48

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        10 février 2024 à 10:36:59

                                        Du coup autant respecter l'utilisation standard

                                        import tkinter as tk
                                        from time import sleep
                                        
                                        root = tk.Tk()
                                        
                                        label = tk.Label(root)
                                        label.pack()
                                        
                                        for i in range(10):
                                            label['text'] = i
                                            label.update_idletasks()
                                            sleep(1.0)
                                        
                                        print('done')
                                        root.mainloop()
                                        



                                        -
                                        Edité par fred1599 10 février 2024 à 11:19:06

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                                        La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                                          10 février 2024 à 11:48:25

                                          fred1599 a écrit:

                                          Du coup autant respecter l'utilisation standard

                                          Il n'y a pas de "standard", juste des problèmes de compréhension

                                          On code comme on le souhaite tant que ça fonctionne et qu'on sait pourquoi

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            10 février 2024 à 13:45:31

                                            mps a écrit:

                                            Il n'y a pas de "standard", juste des problèmes de compréhension

                                            Pour moi le standard c'est le respect de la doc, je ne vois rien dans la doc qui amène à cette manière de faire.

                                            On peut faire fonctionner quelque chose qui sort de l'ordinaire, ce n'est pas pour autant que c'est correct (les sanctions ne sont pas forcément visibles au départ), d'ailleurs tu le dis toi même, ça peut amener à des problèmes techniques, pire, des problèmes conceptuels.

                                            sans foutre une grouille pas possible si on ne les respecte pas

                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                                            La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                                              10 février 2024 à 22:42:16

                                              fred1599 a écrit:

                                              mps a écrit:

                                              Il n'y a pas de "standard", juste des problèmes de compréhension

                                              Pour moi le standard c'est le respect de la doc, je ne vois rien dans la doc qui amène à cette manière de faire.

                                              En quoi ma mouture ne respecte pas la documentation ? Le fait qu'une construction fonctionne n'en fait pas un standard auquel on devrait adhérer et votre truc n'est pas plus "standard" que le mien. Il faudrait peut être arrêter de délirer (ou changer de moquette).

                                              • Partager sur Facebook
                                              • Partager sur Twitter

                                              Tkinter

                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                              • Editeur
                                              • Markdown