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 :

PIL ImageTK et Thread


Sujet :

Tkinter Python

  1. #1
    Nouveau Candidat au Club
    Inscrit en
    Décembre 2013
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2013
    Messages : 6
    Points : 1
    Points
    1
    Par défaut PIL ImageTK et Thread
    Bonjour à tous,

    je suis nouveau venu et débute avec python
    je souhaite créer un dash-bord qui intègre notamment des captures à partir d'une caméra IP
    je développe sous Windows pour des raisons pratiques, mais le code est destiné à une plateforme ARM sous Débian

    l'extrait du code ci-joint fonctionne très bien sous Windows, mais je rencontre un problème sous Débian (plateforme ARM et Intel, le problème est d'ailleurs le même)

    Quand je quitte mon interface, j'active un événement qui interrompt la temporisation et positionne à True le flag du gestionnaire d’événement du thread.
    En fonction de l’endroit où je me situe dans la boucle While, le programme exécute le code restant avant de quitter la section Run() .
    Le programme bloque sur l’instruction tk_photo = ImageTk.PhotoImage(rdim)

    La seule solution que j’a trouvé, c’est positionner un timeout sur le join() et de tester si le thread est toujours en activité. Si c’est le cas , je force son arrêt. Mais je ne comprends pas pourquoi il bloque sur l’instruction ImageTk.photoImage du module PIL
    J’ai repris ce code sans utiliser de thread , je n’ai pas le problème …

    Quelqu’un a-t-il une idée ?

    PS : dans le code , j'utilise une caméra publique pour le tester par tout le monde ...

    Merci d’avance
    photo2.py

  2. #2
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Sous Python 2 les classes héritent de object et oublie définitivement les global

    Donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Application(object):
        def __init__(self):
            self.rep_images ="./images"
            self.threads = []
            self.root=Tk()
    Tes threads ne devraient pas s'arrêter de cette manière, normalement un thread s'éteint faute de carburant.

    Soit il a achevé sa tâche, soit il n'est plus alimenté, ce qui est ton cas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class Objetvideo_live(threading.Thread):
        def __init__(self,controle):
            threading.Thread.__init__(self)
            self.controle= controle
            self._fin = False
            ...
     
        def run(self):
            while not self._fin:
            ...
     
        def arretetoi(self):
            self._fin = True

  3. #3
    Nouveau Candidat au Club
    Inscrit en
    Décembre 2013
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2013
    Messages : 6
    Points : 1
    Points
    1
    Par défaut Re : PIL ImageTK et Thread => mofications KO
    Bonjour VinsS,
    Merci pour ton aide,

    J'ai corrigé mon pgm en supprimant
    - les variables globlals
    - en ajoutant l'héritage "Object" à ma class Application

    le problème reste le même sous l'environnement Débian : blocage ImageTk.PhotoImage( ...) quand je donne l'info au thread de finir son execution
    (evenement self._fin.set() de mon object self._fin = threading.Event()

    Oui, faute de carburant, je devrais pouvoir mettre fin à l'execution Run() du thread
    mais il bloque tjs sur la même instruction ...
    je contourne en forçant l'arrêt du thread par l'instruction _Thread__stop() , mais ce n'est pas logique ...

    fichier mis à jour : photo2.py

  4. #4
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    J'expliquais dans mon post que threading.Event().set() ne sert aucunement à mettre fin à un thread, utilise la méthode que je t'ai indiquée.

  5. #5
    Nouveau Candidat au Club
    Inscrit en
    Décembre 2013
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2013
    Messages : 6
    Points : 1
    Points
    1
    Par défaut Re : PIL ImageTK et Thread => modifications KO
    VinsS


    je pensais que la methode utilisée pour quitter le bloc run() faisait la même chose .
    Elle permetait en plus de ne pas attendre la fin d'une temporisation (quand on utilise un wait exemple "self._fin.wait(2.0)")

    la doc https://docs.python.org/2/library/threading.html fait référence à l'object Event
    Il sert normalement à la communication entre thread mais il peut être détourné ...
    voir explications : http://python.developpez.com/faq/?page=Thread

    j'ai intégré tes modifications => suppression de l'appel au gestionnaire d'évenement et utilisation d'un flag
    le problème est toujours le même .


    Fichier mis à jour

    photo22.py

  6. #6
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par frlep501 Voir le message
    VinsS


    je pensais que la methode utilisée pour quitter le bloc run() faisait la même chose .
    Elle permetait en plus de ne pas attendre la fin d'une temporisation (quand on utilise un wait exemple "self._fin.wait(2.0)")

    la doc https://docs.python.org/2/library/threading.html fait référence à l'object Event
    Il sert normalement à la communication entre thread mais il peut être détourné ...
    voir explications : http://python.developpez.com/faq/?page=Thread

    j'ai intégré tes modifications => suppression de l'appel au gestionnaire d'évenement et utilisation d'un flag
    le problème est toujours le même .


    Fichier mis à jour

    photo22.py
    Bonjour,

    Une idée en passant : si cela fonctionne OK sous Windows mais pas sous Debian ARM/Intel => peut-être que cela vient tout simplement des options de compilation de Tcl/Tk / Tkinter sous Debian ARM/Intel ?

    Une option du style --threading=no-threads (je dis ce nom d'option au pif, là).

    Peut-être faudrait-il regarder de ce côté-là ?

    @+.

  7. #7
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Mais en fait le code fonctionne bien, en tous cas sous Ubuntu (Debian inside), le thread est bien stoppé, il suffit d'ouvrir une deuxième console avec le programme top pour s'en rendre compte, le problème est que en l'absence de _Thread__stop() la console ne rend pas la main et Ctrl+C n'y fait rien.

    Je me souviens avoir déjà eu cet agaçant problème avec des mainloop de tkinter, mais je ne me souviens plus du détail ni comment j'ai solutionné.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par VinsS Voir le message
    Mais en fait le code fonctionne bien, en tous cas sous Ubuntu (Debian inside), le thread est bien stoppé, il suffit d'ouvrir une deuxième console avec le programme top pour s'en rendre compte, le problème est que en l'absence de _Thread__stop() la console ne rend pas la main et Ctrl+C n'y fait rien.

    Je me souviens avoir déjà eu cet agaçant problème avec des mainloop de tkinter, mais je ne me souviens plus du détail ni comment j'ai solutionné.
    Bonjour,

    Tkinter travaille beaucoup en différé : peut-être suffit-il de faire un widget.update() pour forcer la màj des idle_tasks() et éviter ainsi que Tkinter ne s'embourbe dans des tâches ultérieures à exécuter alors que le thread prend fin ?

  9. #9
    Nouveau Candidat au Club
    Inscrit en
    Décembre 2013
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2013
    Messages : 6
    Points : 1
    Points
    1
    Par défaut Re : PIL ImageTK et Thread => Tjs KO
    Bonjour,

    J'ai pris en compte les remarques de tarball69 en effectuant dans la boucle du bloc Run() un Update du widget Canvas
    cela ne change rien ...

    J'ai effectué deux autres tests
    - en supprimant le widget Canvas et en affectant l'imageTk à un Label . Le résultat est toujours le même sous Débian ...
    - en supprimant PIL sous Débian et en installant Pillow => même problème.


    Rq: pour les options de compil de Tcl/Tk , je ne suis contenté d'une install des binaires pour PIL (apt-get install python-image python-image-tk)
    ces paquets sont liés aux dépendances tcl8.5 et tk8.5 => donc pas de compilation dans mon cas.

  10. #10
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par frlep501 Voir le message
    Rq: pour les options de compil de Tcl/Tk , je ne suis contenté d'une install des binaires pour PIL (apt-get install python-image python-image-tk)
    ces paquets sont liés aux dépendances tcl8.5 et tk8.5 => donc pas de compilation dans mon cas.
    Bonjour,

    Je ne dis pas le contraire, je dis simplement que tcl/tk ont pu être compilés avec un --threading=no-threads dans les paquets de Debian (j'avais lu un article à ce sujet sur le net, mais je ne me souviens malheureusement plus où).

    Je me souviens qu'il y était question d'une désactivation des threads notamment pour l'archi ARM.

  11. #11
    Nouveau Candidat au Club
    Inscrit en
    Décembre 2013
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2013
    Messages : 6
    Points : 1
    Points
    1
    Par défaut Re : PIL ImageTK et Thread => support thread actif sous Tcl/Tk
    Bonjour,

    Pour faire suite à la réponse de tarball69,

    J'ai vérifié que le support du thread est bien activé sur l'environnement TCL8.5 de la plateforme ARM (sous Debian)
    en m'appuyant sur ce post : https://mail.python.org/pipermail/tk...er/001684.html


    le programme ne crashe pas et la variable renvoie tcl_platform(threaded) "1"
    On peut donc supposer que le support thread est bien actif pourTk/Tcl
    ci-dessous le code :

    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
    import threading
     
    def test(text_widget):
    	text_widget.config(text='threaded :' + Tkinter.Tk().getvar("tcl_platform(threaded)"))
     
    def try_it(text_widget):
    	threading.Thread(target=test, args=(text_widget, )).start()
     
    lbl = Tkinter.Label()
    lbl.pack()
    lbl.after(10, lambda: try_it(lbl))
     
    lbl.mainloop()

    Avez-vous idée ?
    PS : Je dois insérer un système de pause dans l'affichage de la vidéo.
    Si le comportement est le même , je risque de ne pas pouvoir implémenter cette fonctionnalité ...

    merci d'avance

  12. #12
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par frlep501 Voir le message
    Bonjour,

    Pour faire suite à la réponse de tarball69,

    J'ai vérifié que le support du thread est bien activé sur l'environnement TCL8.5 de la plateforme ARM (sous Debian)
    en m'appuyant sur ce post : https://mail.python.org/pipermail/tk...er/001684.html


    le programme ne crashe pas et la variable renvoie tcl_platform(threaded) "1"
    On peut donc supposer que le support thread est bien actif pourTk/Tcl
    ci-dessous le code :

    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
    import threading
     
    def test(text_widget):
    	text_widget.config(text='threaded :' + Tkinter.Tk().getvar("tcl_platform(threaded)"))
     
    def try_it(text_widget):
    	threading.Thread(target=test, args=(text_widget, )).start()
     
    lbl = Tkinter.Label()
    lbl.pack()
    lbl.after(10, lambda: try_it(lbl))
     
    lbl.mainloop()

    Avez-vous idée ?
    PS : Je dois insérer un système de pause dans l'affichage de la vidéo.
    Si le comportement est le même , je risque de ne pas pouvoir implémenter cette fonctionnalité ...

    merci d'avance
    Bonjour,

    Moi je sèche sur ce coup-là.

    Désolé.

    @+.

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    En principe GUI et threads ne font pas bon ménage.
    tkinter est un peu particulier car, il pourrait pourvu que _tkinter et Tk aient été compilés avec les bonnes options (et que vous ne tombiez pas dans des "bugs").
    Dans la pratique, il est préférable de poster les mises à jour du GUI dans l'event queue.

    Techniquement çà pourrait passer par l'ajout d'une méthode dans le thread qui effectue les mises à jour du GUI dans sa thread:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        def update_display(self, photo):
            self.image = ImageTk.PhotoImage(photo)
            print "tk_photo en memoire"
            self.controle.itemconfig(self.cameraPhoto, image=self.image)
            print "image update"
    Puis on appelle çà à la fin de "run":
    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
       def run(self):
     
                while not self._fin.isSet():
                    #if not self._fin.isSet():
                        response = urlopen(self.ip)
     
                        file = open(self.jpg, 'wb')
                        file.write(response.read())
                        file.close()
                        print "url ok"
                    #if not self._fin.isSet():
                        photo = Image.open(self.jpg)
                        print "Image open"
                    #if not self._fin.isSet():
                        rdim = photo.resize((480,360), Image.ANTIALIAS)
                        self.controle.after_idle(lambda photo=rdim: self.update_display(photo))
    Essayez de faire marcher çà en notant que je n'ai pas testé.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  14. #14
    Nouveau Candidat au Club
    Inscrit en
    Décembre 2013
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2013
    Messages : 6
    Points : 1
    Points
    1
    Par défaut Re : PIL ImageTK et Thread =>ajout d'une méthode dans le thread
    Bonjour,

    Pour faire suite à la réponse de wiztricks,

    J'ai ajouté la methode qui fonctionne mais le problème reste le même quand on sort de la boucle du run()

    bonne soirée

  15. #15
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par frlep501 Voir le message
    J'ai ajouté la methode qui fonctionne mais le problème reste le même quand on sort de la boucle du run()
    postez le code et racontez ce qu'il se passe.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  2. récupérer la valeur de sortie d'un thread
    Par jakouz dans le forum Langage
    Réponses: 3
    Dernier message: 31/07/2002, 11h28
  3. Programmer des threads
    Par haypo dans le forum C
    Réponses: 6
    Dernier message: 02/07/2002, 13h53
  4. Réponses: 5
    Dernier message: 12/06/2002, 15h12
  5. [Kylix] Pb de Thread !!
    Par Anonymous dans le forum EDI
    Réponses: 1
    Dernier message: 25/04/2002, 13h53

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