Thread.tkinter

Bonjour, j'ai un problème. Un thread gère la communication client-serveur. Il envoie la variable globale ''msg'' et reçoit les informations du serveur. Le clic sur un bouton d'une interface graphique tkinter change la valeur de la variable globale ''msg''. Mais lorsque je clique sur l'un des boutons le thread n'envoie pas le message. Aidez-moi s'il vous plaît.

10 réponses

  • Votes
  • Date
  • Date décroissante
Résumé de la discussion

Problème central : une application tkinter utilise un processus en arrière-plan pour gérer une communication client-serveur et la variable globale msg changée par les boutons ne transmet pas l'information. Des échanges soulignent l'intérêt d'une file d'attente (Queue) pour transférer les données entre le processus et l'interface tkinter, et d'éviter les boucles bloquantes qui empêchent l'envoi. D'autres proposent une pause courte par time.sleep(0,1 seconde) pour laisser passer les échanges, et certains envisagent d'intégrer l'interface Tkinter avec des appels déclenchés par les boutons tout en utilisant une queue centralisée. En cas de complexité avec plusieurs boutons, l'essentiel consiste à décharger le traitement des données sur un consommateur dédié alimenté par une queue, afin de préserver la réactivité de l'interface.

Bobot (l’IA à votre service)
  1. En résumé le script permet de commander un robot-car à distance. Le thread est nécessaire pour la communication client-serveur et l'interface pour la commande. Les deux doivent être indépendants.
    1. Dans ce cas, il faut revoir quelques parties de ton code et t'inspirer un peu de ce que j'ai rapidement fait.
      Première chose, tu travailles avec des objets, quand on a progressé à en arriver là, on n'utilise plus jamais ce global et on s'arrange pour passer les objets aux autres instances qui auront besoin d'agir dessus.

      On arrive rapidement a

      import time
      import threading
      import tkinter as tk
      
      class Commandes:
          def __init__(self, thread):
              self.thread = thread
      
          def demarrer(self):
              self.thread.message = "1"
      
          def arreter(self):
              self.thread.message = "4"
      
          def devier_a_gauche(self):
              self.thread.message = "2"
      
          def devier_a_droite(self):
              self.thread.message = "3"
      
      
      Resultat = None
      class Fenetre(tk.Tk):
          def __init__(self, thread, commandes):
              super().__init__()
              self.thread = thread
              self.commandes = commandes
              self.geometry("450x500")
              label = tk.Label(self, text="Resultat: {}".format(Resultat))
              label.pack(side="top", fill="both", expand=True)
              btn1 = tk.Button(self, text="commande1", bg='cyan', command=self.commandes.demarrer)
              btn1.pack()
              btn1.place(x=20, y=200)
              btn2 = tk.Button(self, text="Quitter", bg='yellow', command=self.quit)
              btn2.pack()
              btn2.place(x=150, y=200)
              btn3 = tk.Button(self, text="commande2", bg='orange', command=self.commandes.devier_a_gauche)
              btn3.pack()
              btn3.place(x=320, y=200)
              btn4 = tk.Button(self, text="commande3", bg='yellow', command=self.commandes.devier_a_droite)
              btn4.pack()
              btn4.place(x=20, y=300)
              btn5 = tk.Button(self, text="commande4", bg='orange', command=self.commandes.arreter)
              btn5.pack()
              btn5.place(x=320, y=300)
      
          def quit(self):
              self.wait_thread_end()
              super().quit()
      
          def destroy(self):
              self.wait_thread_end()
              super().destroy()
      
          def wait_thread_end(self):
              # Cette fonction attendra que le thread soit bien fini avant de se fermer
              self.thread.running = False
              if self.thread.is_alive:
                  self.after(100, self.wait_thread_end)
      
      
      class ThreadCommunication(threading.Thread):
          def __init__(self):
              threading.Thread.__init__(self)
              self.message = 'ready'
              self.running = True
      
          def run(self):
              while self.running:
                  if(self.message):
                      print(self.message)
                      self.message = None
                  time.sleep(5)
              print("thread fini")
      
      thrd = ThreadCommunication()
      thrd.start()
      commandes = Commandes(thrd)
      fenetre = Fenetre(thrd, commandes)
      fenetre.mainloop()


      Et tu peux bien voir que tout est un peu une question de logique et de propreté du code, on peut faire autrement, mais il n'y avait pas grand-chose à faire pour en arriver là, bon y a encore des choses à revoir dans ton code.

      Ne sachant pas du tout à quoi sert cette variable Resultat (j'imagine un retour du résultat des commandes ?), j'ai laissé en l'état, mais nul doute qu'il faudra procéder de la même façon.

      J'ai viré les time.sleep, si tu dois les remettre, il faut qu'il soient effectués dans le run, sinon tu vas geler tkinter chaque fois. Bref en fonction du message reçu tu fais le sleep adéquat, pas compliqué à faire.
    2. Contributeur
      Le thread de communication ne fait qu'attendre que la variable msg change, il est donc dépendant, et je ne vois pas de raison d'en faire un thread séparé.
    3. @drepoBonjour
      En touchant juste sur time.sleep (0.1) j'ai eu l'effet souhaité. Je vais mettre mon vrai code à jour et après le test avec le robot (demain) je vous tiendrai au courant. Merci.
    4. Contributeur
      @yazchapi21le même, sans thread:
      import tkinter as tk
      
      class Commandes:
          def __init__(self, reseau):
              self.reseau = reseau
      
          def demarrer(self):
              self.reseau.envoi("1")
      
          def arreter(self):
              self.reseau.envoi("4")
      
          def devier_a_gauche(self):
              self.reseau.envoi("2")
      
          def devier_a_droite(self):
              self.reseau.envoi("3")
      
      Resultat = None
      class Fenetre(tk.Tk):
          def __init__(self, commandes):
              super().__init__()
              self.commandes = commandes
              self.geometry("450x500")
              label = tk.Label(self, text="Resultat: {}".format(Resultat))
              label.pack(side="top", fill="both", expand=True)
              btn1 = tk.Button(self, text="commande1", bg='cyan', command=self.commandes.demarrer)
              btn1.pack()
              btn1.place(x=20, y=200)
              btn2 = tk.Button(self, text="Quitter", bg='yellow', command=self.quit)
              btn2.pack()
              btn2.place(x=150, y=200)
              btn3 = tk.Button(self, text="commande2", bg='orange', command=self.commandes.devier_a_gauche)
              btn3.pack()
              btn3.place(x=320, y=200)
              btn4 = tk.Button(self, text="commande3", bg='yellow', command=self.commandes.devier_a_droite)
              btn4.pack()
              btn4.place(x=20, y=300)
              btn5 = tk.Button(self, text="commande4", bg='orange', command=self.commandes.arreter)
              btn5.pack()
              btn5.place(x=320, y=300)
          def quit(self):
              self.destroy()
              super().quit()
      
      class Communication():
          def __init__(self):
              pass
          def envoi(self,message):
              print(message)
      
      res = Communication()
      commandes = Commandes(res)
      fenetre = Fenetre( commandes)
      fenetre.mainloop()
    5. @drepoLe thread est très nécessaire. Pouvez-vous me vérifier le code ci-dessous ?
      class ThreadCommunication(threading.Thread):
          def __init__(self):
              threading.Thread.__init__(self)
            def run(self):
                  global msg
                  print("run",msg)
                  while True:
                      if(msg):
                          print(msg)
                          utils.send_msg(sock, msg)
                          msg = None
                    time.sleep(0.1)
      		msgFromArduino = utils.recv_msg(sock)
      		msgFromArduino = msgFromArduino.split(':')[1].split(';')
      		print(msgFromArduino)
      		if (not(len(msgFromArduino) < 6)):
      			data1 = msgFromArduino[0]
      			data2 = msgFromArduino[1]
      			data3 = msgFromArduino[2]
      			data4 = msgFromArduino[3]
      			data5 = msgFromArduino[4]
      			start_time = time.time()
      			secondes = time.time() - start_time
      			Distance_ultrason.append(data1)
      			vitesse_droite.append(data2)
      			vitesse_gauche.append(data3)
      			Latitude.append(data4)
      			Longitude.append(data5)
      			temps.append(round(secondes, 2))
      			now = datetime.datetime.now()
      			c = open('fichierrobot_car_' +  '_' + str(now.strftime("%Y-%m-%d-%H-%M")) + '.csv', "w")
      			c = csv.writer(c, delimiter="\t")
      			c.writerow (("Distance_ultrason","vitesse_droite","vitesse_gauche","Latitude","Longitude","temps"))
      			fin1, fin2 = len(Distance_ultrason), len(vitesse_droite)
      			if fin1 == fin2:  
      				for i in range (fin1):
      					c.writerow((Distance_ultrason[i],vitesse_droite[i],vitesse_gauche[i],Latitude[i],Longitude[i],temps[i]))
      					return vitesse_droite, vitesse_gauche, temps 
                      
      thrd = ThreadCommunication(sock)
      thrd.start()

      Qu'est-ce qu'il faut mettre après utils.send_msg(sock, msg) pour que la réception soit faite à la ligne suivante (ligne msgFromArduino = utils.recv_msg(sock)) soit faite. Le but est que l'envoi (utils.send_msg(sock, msg)) et la réception (msgFromArduino = utils.recv_msg(sock)) soient indépendants malgré que les deux sont dans un seul thread. La boucle while lançant l'envoi étant infinie. Merci.
  2. Salut,

    Que doit faire ton script en fait ?
    Quel travail doit faire le thread ?

    Parce d'après tes dernières réponses, je crois qu'utiliser un thread n'a pas d'intérêt sachant que tkinter peut faire la même chose naturellement.

    Par exemple, quelques retouches de ton code en utilisant une simple variable tkinter à laquelle on définit une fonction de callback laquelle sera exécutée chaque fois que celle-ci est modifiée.

    import tkinter as tk
    
    class Commandes():
        def __init__(self, communication):
            self._com = communication
    
        def demarrer(self):
            self._com.send("1")
    
        def arreter(self):
            self._com.send("4")
    
        def devier_a_gauche(self):
            self._com.send("2")
    
        def devier_a_droite(self):
            self._com.send("3")
    
    Resultat = None
    class Fenetre():
        def __init__(self):
            self.root = tk.Tk()
            self.root.geometry("450x500")
            self.communication = Communication(self.root)
            self.communication.run()
            self.commandes = Commandes(self.communication)
            label = tk.Label(self.root, text="Resultat: {}".format(Resultat))
            label.pack(side="top", fill="both", expand=True)
            btn1 = tk.Button(self.root, text="commande1", bg='cyan', command=self.commandes.demarrer)
            btn1.pack()
            btn1.place(x=20, y=200)
            btn2 = tk.Button(self.root, text="Quitter", bg='yellow', command=self.root.quit)
            btn2.pack()
            btn2.place(x=150, y=200)
            btn3 = tk.Button(self.root, text="commande2", bg='orange', command=self.commandes.devier_a_gauche)
            btn3.pack()
            btn3.place(x=320, y=200)
            btn4 = tk.Button(self.root, text="commande3", bg='yellow', command=self.commandes.devier_a_droite)
            btn4.pack()
            btn4.place(x=20, y=300)
            btn5 = tk.Button(self.root, text="commande4", bg='orange', command=self.commandes.arreter)
            btn5.pack()
            btn5.place(x=320, y=300)
    
    class Communication():
        def __init__(self, window):
            self._win = window
            self._msg = tk.Variable(self._win, '', 'msg')
            self._msg.trace('w', self._manage)
            self._stopped = False
    
        def _manage(self, *args):
            if self._stopped:
                print("Can't send message, communication is not running")
                return
            print(self._msg.get())
            if self._msg.get() == "4":
                self._stopped = True
    
        def run(self):
            self._stopped = False
            print('Ready !')
    
        def send(self, msg):
            self._msg.set(msg)
    
    fenetre = Fenetre()
    fenetre.root.mainloop()


    Ce n'est qu'un simple exemple, maintenant si ce n'est pas possible de gérer ça de cette façon, regarde alors du côté de la méthode after de tkinter, dans 99,99% des cas il n'y a pas besoin d'utiliser un thread avec tkinter.
    1. Je l'ai vérifié parce que lorsque je clique sur un bouton et que ça n'a pas marché, je relance le code et là ça marche mais lorsque je clique sur un autre bouton ça ne marche pas, le thread n'envoie pas.
      1. Merci, voilà le bout de code géré par le thread. Mais ça ne marche pas à cause de la variable globale msg. J'attend votre aide s'il vous plait. Merci d'avance.
        1. Contributeur
          ce n'est pas la variable global qui pose problème.
          que penses-tu faire en ligne 33? quand penses-tu que cette ligne est exécutée?

          exemple qui utilise bien cette variable globale:
          import time
          import threading
          msg = None   
              
          def demarrer():
              global msg
              msg = "1"
          def arreter():
              global msg
              msg = "4"
          def devier_a_gauche():
              global msg
              msg = "2"
          
          def devier_a_droite():
              global msg
              msg = "3"
          
          class ThreadCommunication(threading.Thread):
              def __init__(self):
                  threading.Thread.__init__(self)
              def run(self):
                  global msg
                  print("run",msg)
                  while True:
                      if(msg):
                          print(msg)
                          msg = None
                      time.sleep(0.1)
                  print("thread fini")
          thrd = ThreadCommunication()
          thrd.start()
          demarrer()
          time.sleep(1)
          arreter()
          time.sleep(4)
          
        2. @yg_beBonjour yg_be, j'ai pas reçu la notification voilà pourquoi j'ai pas répondu.
          Je vais mettre mon code client intégral à jour, tester et je vous tiendrai au courant. Mais quand j'ai testé votre code à la ligne 30 le code n'affiche pas ("thread fini") ? Merci.
        3. Contributeur
          @yazchapi21le but est justement de montrer que le thread ne se termine pas, qu'il continue à travailler.
        4. @yg_beBonjour
          comme les fonctions modifiant la variable globale doivent être lancées par des boutons, il me faut donc une interface tkinter avec les boutons. J'étais sur la proposition d'utiliser la queue quand j'ai vu votre message. J'ai un code de test avec un seul bouton, l’affichage se fait dans le terminal et non dans le label affichant None lorsqu'on quitte l'interface (c'est pas ça l'essentiel). (Je n'arrige pas à mieux faire les lignes 40, 41, 42).
          import sys, threading
          import numpy as np
          import tkinter as tk
          import time
          from queue import Queue
          
          Resultat = None
          class Fenetre():
              def __init__(self):
                  threading.Thread.__init__(self)
                  self.q = Queue()
                  self.root = tk.Tk()
                  self.root.geometry("450x500")
                  label = tk.Label(self.root, text="Resultat: {}".format(Resultat))
                  label.pack(side="top", fill="both", expand=True)
                  btn1 = tk.Button(self.root, text="commande", bg='cyan', command=self.calcul)
                  btn1.pack()
                  btn1.place(x=20, y=200)
                  btn2 = tk.Button(self.root, text="Quitter", bg='yellow', command=self.root.quit)
                  btn2.pack()
                  btn2.place(x=350, y=200)
                  
              def calcul(self):
                  global Resultat
                  x = np.arange(4)
                  y = np.arange(10,16)
                  A = np.arange(2, 3, 0.1)
                  B = np.append(x, y)
                  Resultat = A+B
                  self.q.put(Resultat)
                  time.sleep(1)
          class Consumer:
              def __init__(self, prod):
                  self.prod = prod
          
              def consume(self):
                  msg = self.prod.q.get()
                  print('Item receved', msg)
                           
          Fenetre().root.mainloop()
          p = Fenetre()
          c = Consumer(p)
          t1 = threading.Thread(target=p.calcul)
          t2 = threading.Thread(target=c.consume)
          t1.start()
          t2.start()
          t1.join()
          t2.join()
          
          

          Mais lorsque j'augmente des boutons (comme j'en ai 4 dans mon vrai code) je ne sais vraiment pas comment créer un seul thread qui vas récupérer le msg comme ce n'est pas une seule fonction qui génère le msg. Si on peut intégrer l'interface tkinter dans votre code avec les boutons appelant les fonctions ça serait mieux. Merci.
        5. Contributeur
          @yazchapi21est-ce dans consume() que tu souhaites récupérer tous les messages?
      2. msg = None   
            
        def demarrer():
            global msg
            msg = str(1)
        
        def arreter():
            global msg
            msg = str(4)
        
        def devier_a_gauche():
            global msg
            msg = str(2)
        
        def devier_a_droite():
            global msg
            msg = str(3)
        
        HOST = sys.argv[-1] if len(sys.argv) > 1 else '192.168.43.199'
        PORT = utils.PORT
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((HOST, PORT))
        print('\nConnected to {}:{}'.format(HOST, PORT))
        print("Type message, enter to send. 'q' to quit")
        
        class ThreadCommunication(threading.Thread):
            """objet thread gérant la communication"""
            def __init__(self, sock):
                threading.Thread.__init__(self)
                self.connexion = sock           # réf. du socket de connexion
            def run(self):
                global msg
                if(msg):
                    utils.send_msg(sock, msg)
                    print(msg)
                #print(msg)
                msg = None
                msgFromArduino = utils.recv_msg(sock)
                msgFromArduino = msgFromArduino.split(':')[1].split(';')
                print(msgFromArduino)
                if (not(len(msgFromArduino) < 6)):
                    data1 = msgFromArduino[0]
                    data2 = msgFromArduino[1]
                    data3 = msgFromArduino[2]
                    data4 = msgFromArduino[3]
                    data5 = msgFromArduino[4]
                    start_time = time.time()
                    secondes = time.time() - start_time
                    Distance_ultrason.append(data1)
                    vitesse_droite.append(data2)
                    vitesse_gauche.append(data3)
                    Latitude.append(data4)
                    Longitude.append(data5)
                    temps.append(round(secondes, 2))
                    now = datetime.datetime.now()
                    c = open('fichierrobot_car_' +  '_' + str(now.strftime("%Y-%m-%d-%H-%M")) + '.csv', "w")
                    c = csv.writer(c, delimiter="\t")
                    c.writerow (("Distance_ultrason","vitesse_droite","vitesse_gauche","Latitude","Longitude","temps"))
                    fin1, fin2 = len(Distance_ultrason), len(vitesse_droite)
                    if fin1 == fin2: 
                        for i in range (fin1):
                            c.writerow((Distance_ultrason[i],vitesse_droite[i],vitesse_gauche[i],Latitude[i],Longitude[i],temps[i]))
                            return vitesse_droite, vitesse_gauche, temps
        thrd = ThreadCommunication(sock)
        thrd.start()
        1. Contributeur
          tu écris "Le clic sur un bouton d'une interface graphique tkinter change la valeur de la variable globale ''msg''.".
          En es-tu certain? Comment l'as-tu vérifié?

          Ton code contient plein de choses qui n'ont rien à voir avec ton soucis. Simplifie-le pour n'en garder que le minimum qui montre le soucis.
          1. Bonjour,

            C'est pourtant simple et ça marche toujours:

            on fait un copier/coller du code ici, on le sélectionne à la souris, on clique sur la petite icone

            "flèche vers le bas" dans la barre d'icones au dessus, on choisit Python dans la liste déroulante

            et cela met le code entre balises

            Ensuite, lorsque le message est validé, le code apparait comme ceci:

            def test():
                print('test')
            
            test()
            
            1. Bonjour, j'ai testé plusieurs fois ces balises pour préserver l'indentation mais ça ne marche pas toujours. Le problème du code est que le thread envoie la variable globale msg au serveur en tenant compte de ses variations lorsqu'on clique sur les boutons de tkinter. Merci.
              1. Voici le code:
                from PIL import Image, ImageTk
                import tkinter as tk
                from tkinter import simpledialog
                from tkinter import messagebox as mb
                from vidgear.gears import CamGear
                import argparse
                import datetime
                import cv2 as cv
                import cv2
                import os
                import csv
                import time
                import sys, socket
                from matplotlib.figure import Figure
                #import matplotlib.animation as animation
                from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
                from matplotlib.animation import FuncAnimation
                import matplotlib.animation as animation
                from matplotlib import style
                import numpy as np
                from random import randint
                import utils
                import threading

                #url = 'http://192.168.43.199:8081'
                #cap = CamGear(source=url).start()

                #Lib install

                #sudo apt-get install python3-pil.imagetk
                #sudo apt-get install libopencv-dev python-opencv

                #Test Tkinter install
                #python3 -m tkinter

                white = "#ffffff"
                lightBlue2 = "#adc5ed"
                font = "Constantia"
                fontButtons = (font, 12)
                maxWidth = 1100
                maxHeight = 700
                temps =[]
                vitesses_droites = np.array([])
                vitesses_gauches = np.array([])
                tps = np.array([])
                xMax = 10
                Distance_ultrason = []
                vitesse_droite = []
                vitesse_gauche = []
                Latitude = []
                Longitude = []
                temps = []
                msg = None

                def demarrer():
                global msg
                msg = str(1)

                def arreter():
                global msg
                msg = str(4)

                def devier_a_gauche():
                global msg
                msg = str(2)

                def devier_a_droite():
                global msg
                msg = str(3)

                HOST = sys.argv[-1] if len(sys.argv) > 1 else '192.168.43.199'
                PORT = utils.PORT
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.connect((HOST, PORT))
                print('\nConnected to {}:{}'.format(HOST, PORT))
                print("Type message, enter to send. 'q' to quit")

                class ThreadCommunication(threading.Thread):
                """objet thread gérant la communication"""
                def __init__(self, sock):
                threading.Thread.__init__(self)
                self.connexion = sock # réf. du socket de connexion
                def run(self):
                global msg
                #while True:
                # if (not(msg == None)):
                if(msg):
                utils.send_msg(sock, msg)
                print(msg)
                #print(msg)
                msg = None
                msgFromArduino = utils.recv_msg(sock)
                msgFromArduino = msgFromArduino.split(':')[1].split(';')
                print(msgFromArduino)
                if (not(len(msgFromArduino) < 6)):
                data1 = msgFromArduino[0]
                data2 = msgFromArduino[1]
                data3 = msgFromArduino[2]
                data4 = msgFromArduino[3]
                data5 = msgFromArduino[4]
                start_time = time.time()
                secondes = time.time() - start_time
                Distance_ultrason.append(data1)
                vitesse_droite.append(data2)
                vitesse_gauche.append(data3)
                Latitude.append(data4)
                Longitude.append(data5)
                temps.append(round(secondes, 2))
                now = datetime.datetime.now()
                c = open('fichierrobot_car_' + '_' + str(now.strftime("%Y-%m-%d-%H-%M")) + '.csv', "w")
                c = csv.writer(c, delimiter="\t")
                c.writerow (("Distance_ultrason","vitesse_droite","vitesse_gauche","Latitude","Longitude","temps"))
                fin1, fin2 = len(Distance_ultrason), len(vitesse_droite)
                if fin1 == fin2:
                for i in range (fin1):
                c.writerow((Distance_ultrason[i],vitesse_droite[i],vitesse_gauche[i],Latitude[i],Longitude[i],temps[i]))
                return vitesse_droite, vitesse_gauche, temps
                thrd = ThreadCommunication(sock)
                thrd.start()
                class Application:
                def __init__(self, output_path = "./"):
                """ Initialize application which uses OpenCV + Tkinter. It displays
                a video stream in a Tkinter window """
                #replace with your video URL
                #url = 'http://192.168.43.199:8081'
                #cap = CamGear(source=url).start()
                self.vs = cv2.VideoCapture('my_input.mp4') # capture video frames, 0 is your default video camera
                self.vs2 = cv2.VideoCapture('my_input.mp4') # capture video frames, camVideo is your out video
                self.output_path = output_path # store output path if want todo a snapshot
                self.current_image = None # current image from the camera
                self.current_image2 = None # current image from the camVideo

                self.root = tk.Tk() # initialize root window

                self.root.resizable(width=False, height=False) #block auto-resizable
                self.root.geometry('%dx%d+%d+%d' % (maxWidth,maxHeight,0,0)) #window size
                self.root.title("Project Interface") # set window title
                self.root['bg'] = 'purple'

                # self.destructor function gets fired when the window is closed
                self.root.protocol('WM_DELETE_WINDOW', self.destructor)

                self.panel = tk.Label(self.root, width=500,height=250) # initialize image panel
                self.panel.pack(padx=5, pady=0, side=tk.LEFT)
                self.panel.place(x=10, y=160)
                self.img = cv2.imread("000.jpg")
                self.resize_img =cv2.resize(self.img, (500, 250))
                self.current_img = Image.fromarray(self.resize_img)
                img_tk = ImageTk.PhotoImage(image=self.current_img)
                self.panel.imgtk = img_tk
                self.panel.config(image=img_tk)

                self.panel1 = tk.Label(self.root, width=500,height=250) # initialize image panel1
                self.panel1.pack(padx=5, pady=0, side=tk.RIGHT)
                self.panel1.place(x=570, y=160)
                self.img1 = cv2.imread("001.jpg")
                self.resize_img1 =cv2.resize(self.img1, (500, 250))
                self.current_img1 = Image.fromarray(self.resize_img1)
                img_tk1 = ImageTk.PhotoImage(image=self.current_img1)
                self.panel1.imgtk1= img_tk1
                self.panel1.config(image=img_tk1)

                self.panel2 = tk.Label(self.root, width=150,height=150)
                self.panel2.pack(padx=5, pady=0, side=tk.LEFT)
                self.panel2.place(x=10, y=10)
                self.img = cv.imread("uam.jpg")
                self.resize_img =cv.resize(self.img, (150, 150))
                self.current_img = Image.fromarray(self.resize_img)
                img_tk = ImageTk.PhotoImage(image=self.current_img)
                self.panel2.imgtk = img_tk
                self.panel2.config(image=img_tk)

                self.panel3 = tk.Label(self.root, width=150,height=150)
                self.panel3.pack(padx=5, pady=0, side=tk.LEFT)
                self.panel3.place(x=930, y=10)
                self.img = cv.imread("fast.jpg")
                self.resize_img =cv.resize(self.img, (150, 150))
                self.current_img = Image.fromarray(self.resize_img)
                img_tk = ImageTk.PhotoImage(image=self.current_img)
                self.panel3.imgtk = img_tk
                self.panel3.config(image=img_tk)

                #graphique courbe
                #print parameters values using a listbox
                self.liste = tk.Listbox(self.root, width=35,height=15)
                self.liste.insert(1, "Distance Ultrason : "+ str(100))
                self.liste.insert(2, "Vitesse roues droites : "+ str(65))
                self.liste.insert(3, "Vitesse roues gauches : "+ str(65))
                self.liste.insert(4, "Latitude : "+ str(10.4))
                self.liste.insert(5, "Longitude : "+ str(51.5))
                self.liste.pack()
                self.liste.place(x=550, y=600)
                '''
                def clearlist():
                listb2.delete(0,END)
                for nom in cur.fetchall():
                listb.insert(END,nom)

                self.liste = tk.Listbox(self.root, width=35,height=15)
                self.liste.insert(1, print('Distance_ultrason[i]=, Distance_ultrason[i]'))
                self.liste.insert(2, print('vitesse_droite[i]=, vitesse_droite[i]'))
                self.liste.insert(3, print('vitesse_gauche[i]=, vitesse_gauche[i]'))
                self.liste.insert(4, print('Latitude[i]=, Latitude[i]'))
                self.liste.insert(5, print('Latitude[i]=, Latitude[i]'))
                self.liste.pack()
                self.liste.place(x=550, y=600)
                '''

                #
                #create a button, that when pressed, start a car driving
                #Todo : define the function
                btn = tk.Button(self.root, text="Demarrer", bg='red', command=demarrer)
                btn.pack()
                btn.place(x=580, y=550)

                #create a button, that when pressed, stop a car driving
                #Todo : define the function
                btn1 = tk.Button(self.root, text="arreter", bg='cyan', command=arreter)
                btn1.pack()
                btn1.place(x=680, y=550)

                #create a button, that when pressed, change a car direction
                #Todo : define the function
                btn2 = tk.Button(self.root, text="devier_a_gauche", bg='green', command=devier_a_gauche)
                btn2.pack()
                btn2.place(x=780, y=550)

                # create a button, that when pressed, will take the current frame and save it to file
                btn3 = tk.Button(self.root, text="devier_a_droite", bg='orange', command=devier_a_droite)
                btn3.pack()
                btn3.place(x=950, y=550)

                btn4 = tk.Button(self.root, text="Quitter", bg='yellow', command=self.root.quit)
                btn4.pack()
                btn4.place(x=500, y=550)

                # start a self.video_loop and self.video2_loop that constantly pools the video sensor
                # for the most recently read frame
                #self.video_loop()
                #self.video2_loop()

                def video_loop(self):
                """ Get frame from the video stream and show it in Tkinter """
                ok, frame = self.vs.read() # read frame from video stream
                if ok: # frame captured without any errors
                cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA) # convert colors from BGR to RGBA
                self.current_image = Image.fromarray(cv2image) # convert image for PIL
                imgtk = ImageTk.PhotoImage(image=self.current_image) # convert image for tkinter
                self.panel.imgtk = imgtk # anchor imgtk so it does not be deleted by garbage-collector
                self.panel.config(image=imgtk) # show the image
                self.root.after(30, self.video_loop) # call the same function after 30 milliseconds

                def video2_loop(self):
                """ Get frame from the video stream and show it in Tkinter """
                ok, frame = self.vs2.read() # read frame from video stream
                if ok: # frame captured without any errors
                cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA) # convert colors from BGR to RGBA
                self.current_image2 = Image.fromarray(cv2image) # convert image for PIL
                imgtk = ImageTk.PhotoImage(image=self.current_image2) # convert image for tkinter
                self.panel1.imgtk = imgtk # anchor imgtk so it does not be deleted by garbage-collector
                self.panel1.config(image=imgtk) # show the image
                self.root.after(30, self.video2_loop) # call the same function after 30 milliseconds

                def destructor(self):
                """ Destroy the root object and release all resources """
                print("[INFO] closing...")
                self.root.destroy()
                self.vs.release() # release
                self.vs2.release() # release
                cv2.destroyAllWindows() # it is not mandatory in this application

                # construct the argument parse and parse the arguments
                ap = argparse.ArgumentParser()
                ap.add_argument("-o", "--output", default="./",
                help="path to output directory to store snapshots (default: current folder")
                args = vars(ap.parse_args())

                # start the app
                print("[INFO] starting...")
                pba = Application(args["output"])

                def get_back_values():
                global vitesses_droites, vitesses_gauches, xMax, tps
                # vitesse_droite, vitesse_gauche, temps = connexion()
                "Dummy function"
                if (len(vitesses_droites) < xMax):
                vitesses_droites = np.append(vitesses_droites, vitesse_droite)
                vitesses_gauches = np.append(vitesses_gauches, vitesse_gauche)
                tps = np.append(tps, temps)
                else:
                vitesses_droites[0:10] = vitesses_droites[0:xMax]
                vitesses_droites[9] = vitesse_droite
                vitesses_gauches[0:10] = vitesses_gauches[0:xMax]
                vitesses_gauches[9] = vitesse_gauche
                tps[0:10] = tps[0:xMax]
                tps[9] = temps
                x = [tps[i] for i in range(10)]
                print(temps[i])
                y1 = [vitesses_droites[i] for i in range(10)]
                print(vitesse_droite[i])
                y2 = [vitesses_gauches[i] for i in range(10)]
                print(vitesse_gauche[i])
                return x, y1, y2
                def update_graph(event=True):
                global vitesses_droites
                if (not(len(vitesses_droites) < 10)):
                x, y1, y2 = get_back_values()
                ax1.clear()
                ax2.clear()
                ax1.set_ylim(0, 10, auto=False)
                #ax1.xaxis.set_ticks(range(6))
                #ax1.xaxis.set_ticklabels(['0', '2', '4', '6', '8', '10'])
                ax2.set_ylim(0, 10,auto=False)
                #ax2.xaxis.set_ticks(range(6))
                #ax2.xaxis.set_ticklabels(['0', '2', '4', '6', '8', '10'])
                ax2.set_xlabel('Temps')
                ax1.set_ylabel('vitesse_droite', color='g', fontsize = 22)
                ax2.set_ylabel('vitesse_gauche', color='r', fontsize = 22)
                ax1.plot(x, y1, 'g-o')
                ax2.plot(x, y2, 'r-o')

                style.use("ggplot")

                fig = Figure(figsize=(8, 5), dpi=50)
                ax1 = fig.add_subplot(211)
                ax2 = fig.add_subplot(212, sharex=ax1)
                ax2.set_xlabel('Temps')
                ax1.set_ylim(0, 10, auto=False)
                #ax1.xaxis.set_ticks(range(6))
                #ax1.xaxis.set_ticklabels(['0', '2', '4', '6', '8', '10'])
                ax1.set_ylabel('vitesse_droite', color='g', fontsize = 22)
                ax2.set_ylabel('vitesse_gauche', color='r', fontsize = 22)
                ax2.set_ylim(0, 10, auto=False)
                #ax2.xaxis.set_ticks(range(6))
                #ax2.xaxis.set_ticklabels(['0', '2', '4', '6', '8', '10'])
                fig.tight_layout()

                graph = FigureCanvasTkAgg(fig, master=pba.root)
                #graph = FigureCanvasTkAgg(fig, height= 100, width=100; background='red', itmaster=app)
                canvas = graph.get_tk_widget()
                canvas.grid(row=0, column=0)

                FuncAnimation(fig, update_graph, interval=2000)
                ani = animation.FuncAnimation(fig, update_graph, interval=500)
                canvas.pack()
                canvas.place(x=45, y=440)
                pba.root.mainloop()

                #if __name__ == "__main__":
                #fen = Application()
                #fen.start()