Rafraîchir un label dans une fenêtre (Tkinter) créée dans un Thread
Bonjour à toutes et à tous,
Peut être, avant d'entrer dans le vif du sujet, une petite présentation car je suis nouveau sur ce forum.
Vous pouvez m'appeler Sam et je ne suis plus tout jeune (mon premier ordinateur était un commodore 64)
J'ai fait de la programmation dans ma jeunesse (sur le commodore 64, puis sur un Atari 1024 STF, puis Basic, Pascal, Turbo C, C++, Delphi, Visual Basic, et même en LSE pour ceux qui connaissent) et j'ai même eu un diplôme universitaire pour ça (en C++).
Mais j'ai choisi de travailler dans un autre domaine et j'ai continué de programmer à mes heures perdues. Force est de constater que quand on ne pratique pas régulièrement, on oubli rapidement...
Aujourd'hui j'ai décidé de revenir à mes première amours, mais le langage à changer et les concepts aussi...
Je travaille sur un Raspberry Pi 2 couplé à un module GPS.
Pas de problème particulier, je récupère bien les informations du GPS.
La où ça coince, c'est quand je veux afficher ces données dans une fenêtre créée avec Tkinter
J'utilise 2 Threads :
- un qui lit les données GPS en permanence (Celui là je l'ai chopé sur le Net)
- un autre pour afficher la fenêtre (Je me suis dit que ce serait un bon exercice pour comprendre les threads et se remettre dans le bain)
Mon code est le suivant :
Code:
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
#! /usr/bin/python
# -*- coding: utf-8 -*-
# Written by Dan Mandle http://dan.mandle.me September 2012
# License: GPL 2.0
#Importation des differentes librairies
from gps import *
from Tkinter import *
import threading
#import os
#from time import *
#import time
gpsd = None #Initialise la variable globale
def FIN(): #Definition de la fonction FIN
gpsp.running = False #stop le thread gpsp
fen.running = False #stop le thread fen
gpsp.join() #attend la fin du thread gpsp
fen.join() #attends la fin du thread fen
class GpsPoller(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
global gpsd #donne acces à la variable global gpsp
gpsd = gps(mode=WATCH_ENABLE) #commence la collect des données du GPS
self.current_value = None
self.running = True #setting the thread running to true
def run(self):
global gpsd
while gpsp.running:
gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer
print '1' #Affiche un 1 pour voir si le thread fonctionne
class Window(threading.Thread):
def __init__(self):
threading.Thread.__init__ (self)
self.current_value = None
self.running = True
def run (self):
Fenetre=Tk() #Création de la fenetre
Fenetre.geometry("300x100") #Defini la taille de la fenetre
Fenetre.title ('Coordonnées GPS') #Définition du titre de la fenêtre
VarLatitude=gpsd.fix.latitude #Acquisition de la Latitude
VarLongitude=gpsd.fix.longitude #Acquisition de la Longitude
VarTime=gpsd.utc #Acquisition de l'heure UTC
TextLatitude=Label(Fenetre, text='Latitude : ' +str(VarLatitude)) #Création du Label Latitude
TextLatitude.pack(side = TOP) #Positionnement
TextLongitude=Label(Fenetre, text='Longitude : '+str(VarLongitude)) #Création du Label Longitude
TextLongitude.pack(side = TOP) #Positionnement
TextTime=Label(Fenetre, text='Heure : '+str(VarTime)) #Création du Label Time
TextTime.pack(side = TOP) #Positionnement
Button2=Button(Fenetre, text='FIN', command=FIN) #Création du bouton FIN
Button2.pack(side = BOTTOM) #Positionnement
while True:
VarLatitude=gpsd.fix.latitude #Acquisition de la Latitude
VarLongitude=gpsd.fix.longitude #Acquisition de la Longitude
VarTime=gpsd.utc #Acquisition de l'heure UTC
TextLatitude.configure(text='Latitude : ' +str(VarLatitude)) #MAJ du Label Latitude
TextLongitude.configure(text='Longitude : '+str(VarLongitude)) #MAJ du Label Longitude
TextTime.configure(text='Heure : '+str(VarTime)) #MAJ du Label Time
print '2' #Affiche un 2 pour voir si le thread fonctionne
#C'est la que ca coince
#Quand Fenetre.update_idletasks() est actif, le bouton FIN ne repond pas MAIS les données GPS sont MAJ
#Quand Fenetre.mainloop() est actif, le bouton FIN répond MAIS les données GPS ne sont pas MAJ
#Fenetre.mainloop() #Activation de la Fenetre
Fenetre.update_idletasks()
#Fin du problème
# Main Program
if __name__ == '__main__':
gpsp = GpsPoller() #Creation du thread GPS
fen = Window() #Creation du thread de la fenetre
gpsp.start() #Lancement du thread gpsp
fen.start() #Lancement du thread fen |
Si vous lisez cette ligne cette ligne, c'est que peut être que mon code n'est pas si imbuvable que ça...
En résumé, mon problème est le suivant :
Soit les données GPS se mettent à jour dans la fenêtre, mais je ne peux pas quitter le programme avec le bouton FIN, soit je peux quitter le programme avec le bouton FIN (il y a une erreur en sortie, mais pour l'instant c'est un point de détail), mais les données GPS ne se mettent pas à jour.
Je vois bien la différence qu'il y a entre ".mainloop()" et ".update_idletasks()". Le premier "lit" les événements et donc le bouton FIN est opérationnel, le second met à jour la fenêtre et ses différents éléments mais n'est pas à l'écoute des événements. Et pour autant, je n'arrive pas à m'en sortir.
Je ne vous cacherai pas que je ne suis pas très à l'aise avec les termes modernes tels que "classe", "instance", "widget". Mais je suis prêts à m'y mettre si quelqu'un peut me l'expliquer simplement...
Quoi qu'il en soit, si l'un ou l'une de vous avez une solution à m'apporter, je suis preneur.
Un grand merci à vous pour m'avoir lu jusqu'à la dernière ligne, et peut être qu'un jour je pourrai vous renvoyer la pareil
Sam