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 :

Dysfonctionnement compte à rebours si perte focus


Sujet :

Tkinter Python

  1. #1
    Futur Membre du Club
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    Points : 7
    Points
    7
    Par défaut Dysfonctionnement compte à rebours si perte focus
    Bonjour

    Je code actuellement un compte à rebours pour animer un escape game. Ce compte à rebours doit pouvoir se lancer et se stopper via kill sous linux par ssh. Le programme est lancé au démarrage d'un raspberry, jusqu'ici tout va bien. Lorsque j'envoie la commande via ssh
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    kill -12 `cat ~/decompteur.pid`
    quel que soit le signal, SIGUSR1, SIGUSR2 ou SIGTERM, il faut que je "clique" sur l'écran pour que la commande s'exécute. Je suis assez limité en code, autodidacte occasionnel, et je touche là une limite sur la conception même du programme, je pense. Mon code complet:
    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
    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
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
     
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    '''
    Affiche un décompte de 60mn à 0 en plein écran.
     
    '''
    import tkinter
    import threading
    import time
    import tkinter.tix
    import os
    import signal
    import sys
    from functools import partial
     
    #La gestion par PID
    chem = os.path.expanduser('~')
    '''le pid mis dans un fichier'''
    getPID = os.getpid()
    monPid = open(chem+"/decompteur.pid", "w")
    monPid.write(str(getPID))
    monPid.close()
     
    ###############################################################################
    def sec2hms(sd):
        """Transforme les secondes sd en chaine "hh:mm:ss" pour affichage"""
        h=0
        m=0
        s=sd
        if s >= 60:
            m = s//60
            s -= m*60
            if m >= 60:
                h = m//60
                m -= h*60
        return "%02d:%02d:%02d" % (h, m, s)
     
    def sig_stoppe(self, signum):
        """Arrête le compte à rebours avant la fin normale"""
        chrono.stop()
     
    def sig_quitte(self, signum):
        os.remove(chem+"/decompteur.pid")
        sys.exit(0)
     
    def sig_lance(self, signum):
        chrono.start()
     
    ##################################################################
    class Comptearebours(threading.Thread):
     
        def __init__(self, h, m, s):
            threading.Thread.__init__(self)
            self.t = h*3600 + m*60 + s
            self.encore = True
     
        def run(self):
            global varsaisie
            t1 = int(time.time())
            varsaisie.set(sec2hms(self.t))
            while self.encore:
                t2 = int(time.time())
                if t2>t1:
                    self.t -= t2-t1
                    if self.t <= 0:
                        self.t = 0
                        self.encore = False
                    varsaisie.set(sec2hms(self.t))
                    t1 = t2
                time.sleep(0.01)
     
        def stop(self):
            self.encore = False
     
    ##############################################################################
    # lancement et affichage de la fenetre
    #
    if __name__ == "__main__":
        #On réagit à un kill -15 (SIGTERM) pour quitter, -10 (SIGUSR1) pour stopper, -12 (SIGUSR2) pour lancer
        signal.signal( signal.SIGTERM, sig_quitte )
        signal.signal( signal.SIGUSR1, sig_stoppe )
        signal.signal( signal.SIGUSR2, sig_lance )
     
        #On lance FuseeLunaire.py
    #    os.system("python "+chem+"/FuseeLunaire.py &");
     
        #affichage
        topDecompte= tkinter.Toplevel(bg="lightgrey",borderwidth=3,padx=5,pady=5,relief="solid",cursor="none")
        topDecompte.geometry(str(topDecompte.winfo_screenwidth())+"x"+str(topDecompte.winfo_screenheight())+"+0+0")
        topDecompte.overrideredirect(True)
        topDecompte.grab_set()
        topDecompte.focus_set()
     
        #frame
        topf=tkinter.Frame(topDecompte, bg="lightgrey")
     
        #Le titre
        zoneTitre=tkinter.Label(topf, text="Démarrage des moteurs dans : ", fg="darkgreen", bg="lightgrey", font = ("Helvetica", 23, "bold"))
        zoneTitre.pack(side="left", pady=2, padx=2)
        topf.pack(side="top", expand=1, fill="both")
     
        #La variable d'affichage
        varsaisie = tkinter.StringVar()
        varsaisie.set("")
     
        #Affichage pour décompte
        saisie=tkinter.Entry(topDecompte, disabledbackground="lightgrey", borderwidth=0, state="disabled", disabledforeground="darkred", textvariable=varsaisie, justify="center", font = ("Helvetica", 70, "bold"))
        saisie.pack(expand=1, side="top")
     
        #gérer le décompte
     
        #topDecompte.grid_columnconfigure(0,weight=1)
        topDecompte.resizable(True,True)
        topDecompte.update()
     
        """Lance le compte à rebours"""
        chrono = Comptearebours(1,0,0)
        chrono.setDaemon(True)
        topDecompte.mainloop()
    Si vous pouviez m'aiguiller, ça me sortirait une épine du pied... Merci!

    Benoît

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

    Pour moi çà fonctionne comme documenté. Maintenant vous devriez pouvoir virer le thread pour le remplacer par un polling effectué via .after.

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

  3. #3
    Futur Membre du Club
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    Points : 7
    Points
    7
    Par défaut
    Ok, je crois avoir saisi la raison du dysfonctionnement, relation avec le thread. Merci.
    Par contre, "polling via un .after." je ne vois pas par quel bout prendre le truc. Je ne suis même pas sur d'avoir compris ce qu'est un polling... J'abuse : est-ce que vous pourriez m'expliquer un peu de quoi il retourne?

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

    D'abord vous pourriez regarder ce qui se raconte sur Internet... et c'est ce que vous faites quand vous écrivez:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            while self.encore:
                ...
                time.sleep(0.01)
    Vous êtes comme Mr Jourdain de Molière?

    Avec .after, vous allez remplacer la boucle while par des appels répétitifs à une même fonction tant que... histoire de ne pas bloquer le thread principal (du GUI).

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

  5. #5
    Futur Membre du Club
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    Points : 7
    Points
    7
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Vous êtes comme Mr Jourdain de Molière?
    C'est tout moi...

    J'avais fini par saisir le sens de polling. Mais je ne vois pas comment appliquer ça à mon chronomètre. Ya un truc qui bloque là-haut... Mais je creuse

    EDIT:
    J'ai modifié le script. Viré le thread, adapté le tout, le résultat est le même. Effectivement, il faut que je clique sur l'écran tactile du rasp pour que le compte à rebours démarre. Quelle subtilité loupe'je?

    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
    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
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    '''
     
    Affiche un décompte de 60mn à 0 en plein écran.
     
    '''
    import tkinter as tk
    import os
    import signal
    import sys
    from functools import partial
     
    #La gestion par PID
    chem = os.path.expanduser('~')
    '''le pid mis dans un fichier'''
    getPID = os.getpid()
    monPid = open(chem+"/decompteur.pid", "w")
    monPid.write(str(getPID))
    monPid.close()
     
    ###############################################################################
    def sec2hms(sd):
        """Transforme les secondes sd en chaine "hh:mm:ss" pour affichage"""
        h=0
        m=0
        s=sd
        if s >= 60:
            m = s//60
            s -= m*60
            if m >= 60:
                h = m//60
                m -= h*60
        return "%02d:%02d:%02d" % (h, m, s)
     
    def sig_stoppe(self, signum):
        """Arrête le compte à rebours avant la fin normale"""
        saisie.stop()
     
    def sig_quitte(self, signum):
        """Quitter l'application"""
        os.remove(chem+"/decompteur.pid")
        saisie.destroy()
        sys.exit(0)
     
    def sig_lance(self, signum):
        """Lancer le compte à rebours"""
        saisie.demarre()
     
    ##################################################################
    class Comptearebours(tk.Label):
        t = 3600
        encore = True
     
        def demarre(self,delay=1000):
            if self.encore :
                self.t = self.t - 1
                if  self.t <= 0 :
                    self["text"] = "Trop tard !!"
                else :
                    self["text"] = sec2hms(self.t)
                    self.after(delay,self.demarre)
     
        def stop(self):
            self.encore = False
     
        def destroy(self):
            self.stop()
            super().destroy()
     
    ##############################################################################
    # lancement et affichage de la fenetre
    #
    if __name__ == "__main__":
        #On réagit à un kill -15 (SIGTERM) pour quitter, -10 (SIGUSR1) pour stopper, -12 (SIGUSR2) pour lancer
        signal.signal( signal.SIGTERM, sig_quitte )
        signal.signal( signal.SIGUSR1, sig_stoppe )
        signal.signal( signal.SIGUSR2, sig_lance )
     
        #On lance FuseeLunaire.py
    #    os.system("python "+chem+"/FuseeLunaire.py &");
     
        #affichage
        topDecompte= tk.Toplevel(bg="lightgrey",borderwidth=3,padx=5,pady=5,relief="solid",cursor="none")
        topDecompte.geometry(str(topDecompte.winfo_screenwidth())+"x"+str(topDecompte.winfo_screenheight())+"+0+0")
        topDecompte.overrideredirect(True)
        topDecompte.grab_set()
        topDecompte.focus_set()
     
        #frame
        topf=tk.Frame(topDecompte, bg="lightgrey")
     
        #Le titre
        zoneTitre=tk.Label(topf, text="Il vous reste : ", fg="darkgreen", bg="lightgrey", font = ("Helvetica", 23, "bold"))
        zoneTitre.pack(side="left", pady=2, padx=2)
        topf.pack(side="top", expand=1, fill="both")
     
        #Affichage pour décompte
        saisie=Comptearebours(topDecompte, background="lightgrey", borderwidth=0, state="disabled", disabledforeground="darkred", justify="center", font = ("Helvetica", 70, "bold"))
        saisie.pack(expand=1, side="top")
     
        #gérer le décompte
     
        #topDecompte.grid_columnconfigure(0,weight=1)
        topDecompte.resizable(True,True)
        topDecompte.update()
     
        """Lance le compte à rebours"""
        topDecompte.mainloop()

  6. #6
    Futur Membre du Club
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    Points : 7
    Points
    7
    Par défaut
    Précisions pour ce "focus". J'ai testé aussi sur mon ordi, en passant par ssh. Une fois la commande lancée, si je ne remue pas la souris, le label n'affiche et ne démarre pas le compte à rebours. J'ai testé des forçages de focus sur le label, sur la fenêtre, mais rien.

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

    Pas trop le temps de regarder les détails mais... la logique pour arrêter ou démarrer un compte à rebours devrait fonctionner même si ces commandes sont déclenchées via des Button qui changeraient l'état d'une variable globale testée par la fonction appelée via .after.

    Je n'ai pas testé mais je ne vois pas pourquoi le comportement changerait avec le focus (çà ne contrôle que le widget qui capture les saisies pas les sorties) ou parce que le Label a mettre à jour est affiché dans la fenêtre principale (vs. secondaire).

    Après il y a ce qui "fonctionne" a peu près partout et ce qui ne marche pas sur le Linux du RPI notamment remplacer le changement d'état effectué par des Button ou via des signaux.

    Je reconnais que çà fait pas mal de pistes à explorer (et de soucis à éliminer). Mais désolé, pas le temps de faire ce boulot là pour vous (d'autant que je n'ai pas de RPI sous la main pour tester vos codes qui ne fonctionnent déjà pas sous Windows après la mise en commentaires de nombres d'instructions).


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

  8. #8
    Futur Membre du Club
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    Points : 7
    Points
    7
    Par défaut
    Le problème se produit indifféremment sur le RPI et sur mon ordi sous Linux, ce n'est donc pas inhérent à des subtilités liées à la framboise. J'ai testé le lancement du compte à rebours juste après le "saisie.pack()" et ça fonctionne normalement. Peut-être qu'un Pythoniste-linuxien aura une idée. En attendant, je vais continuer mes tests, si j'avance, je reviens poster ici. Merci, en tout cas!

Discussions similaires

  1. [timer] Compte à rebours pour redirection !
    Par Raideman dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 31/12/2005, 20h07
  2. Compte à rebours
    Par Anduriel dans le forum Général JavaScript
    Réponses: 11
    Dernier message: 29/12/2005, 20h12
  3. compte à rebours
    Par Datord dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 17/11/2005, 21h22
  4. compte à rebours
    Par etoile1506 dans le forum C
    Réponses: 10
    Dernier message: 27/10/2005, 15h20
  5. Compte à rebours trop rapide
    Par Anduriel dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 12/06/2005, 20h57

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