Forum Programmation.python tkinter - compte à rebours qui ne démarre pas

Posté par  . Licence CC By‑SA.
Étiquettes :
1
17
mai
2021

Bonjour,

J'ai un script qui m'affiche en plein écran un compte à rebours. Idéalement, je veux que le script soit lancé au démarrage d'un rasberry sous raspian. Ça, c'est bon. Puis, via kill j'envoie un SIGUSR2 pour démarrer le décompte proprement dit. Et c'est là que ça coince. Sans autre action de ma part, le décompte n'apparait pas. Par contre, si je clique sur l'écran, le décompte apparait et descend bien à 0. J'ai testé sur mon ordi sous debian, même comportement, là il suffit que je remue la souris, et ça lance le décompte. A priori, le code en lui-même fonctionne, mais une subtilité m'échappe… Si quelqu'un a une idée, je suis preneur.

#! /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()

J'ai trouvé momentanément une parade en lançant le décompte juste après le "saisie.pack()", là ça marche normalement…

  • # Un événement idle

    Posté par  (site web personnel) . Évalué à 2. Dernière modification le 18 mai 2021 à 13:25.

    Voir si mettre en place un événement clock idle permette que Tkinter rende la main à la boucle d'interprétation et permette le traitement des signaux.

    topf.after(<delai>, <callback>)

    Dans ton cas le callback devrait pouvoir être un lambda qui ne fait rien (ou qui relance un .after() qq temps après), le but étant juste que Tkinter rende la main.

    Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

  • # youpi.

    Posté par  . Évalué à 1.

    Salut,

    Merci de ta réponse, et bien joué. Ça marche.
    Second merci, du coup, pour la solution!

    B

  • # oups...

    Posté par  . Évalué à 1.

    bon, en fait non. J'avais juste testé sur mon ordi, ça marchait. Par contre, sur le raspberry, rien de changé, il faut activer par clic ou souris. Les versions sont différentes, 3.7.2 sur le rasp, 3.9.2 sur l'ordi, ça peut expliquer? Je vais voir si je peux accorder les versions pour vérifier

    • [^] # Re: oups...

      Posté par  (site web personnel) . Évalué à 2.

      Idee: Voir s'il faudrait un appel a sigwait() ou sigpending(), éventuellement dans le callback.

      Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

  • # je teste!

    Posté par  . Évalué à 1.

    j'étais parti loin mais j'ai lu! Ok, je teste

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.