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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    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
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    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
    Membre averti
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    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
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    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
    Membre averti
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    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
    Membre averti
    Inscrit en
    Septembre 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 16
    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.

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