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 :

programmer le lancement de fonctions avec after() [Python 3.X]


Sujet :

Tkinter Python

  1. #1
    Membre confirmé
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Par défaut programmer le lancement de fonctions avec after()
    Bonjour à vous

    Je suis en train de créer une interface dans laquelle apparaîtrons divers messages à des intervalles pré-programmés.
    Des mp3 seront également lancés.

    J'ai fait des recherches sur TKinter et j'ai compris trois choses :
    1- Il vaut mieux éviter les fonctions bloquantes comme time.sleep()
    2- Il vaut mieux utiliser la méthode after() faite exprès dans tkinter
    3- Il sera nécessaire d'utiliser des threads pour qu'un chronomètre puisse défiler à l'écran pendant qu'un mp3 est lu.

    Il me semble, après documentation et plusieurs expérimentations, avoir compris l'usage des threads.

    J'ai donc créé un petit programme pour étudier la méthode after() mais je reste bloqué. C'est un simulateur d'automatisation d'aquarium.
    Ce programme devrait, selon moi, informer du jour dans la première étiquette et, chaque jour, afficher les divers événements déclenchés au fur et à mesure (lumière, nourriture...) dans la seconde étiquette. Devraient défiler comme ça, tous les jours de la semaine.
    (Les intervalles (2000), seront remplacés ultérieurement par des variables rassemblées dans un tableau.)

    Cependant, mon programme ne fonctionne pas : La fenêtre ne s'ouvre qu'à la toute fin de l’exécution du programme.

    Je me casse la tête depuis bien longtemps et il n'y a aucun message d'erreur pour m'orienter.
    J'ai utilisé le débugueur de Thonny, mais j'ai l'impression que tout se passe bien.

    Voici mon 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
    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
     
    """
    Programme pour comprendre l'utilisation de after()
     
    Essai avec des StringVar() --> Exactement le même problème :
    La fenêtre ne s'ouvre que tout à la fin
     
    Je ne souhaite pas utiliser l'heure car dans mon vrai programme, seul le temps relatifs (les intervalles) m'intéresseront
    """
     
    import tkinter as tk
     
    root = tk.Tk()
    root.title("Exemple d'utilisation de after()")
    root.geometry("300x70")
     
    semaine = ["lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"]
     
    label1_vc = tk.StringVar(value = "Jour de la semaine")
    label2_vc = tk.StringVar(value = "Événement")
     
    # Créer une vignette (label) pour afficher le texte
    label1 = tk.Label(textvariable = label1_vc)
    label1.pack(pady=5)
     
    # Créer une vignette (label) pour afficher le texte
    label2 = tk.Label(textvariable = label2_vc)
    label2.pack(pady=5)
     
    cumul = 1000
     
    def aqua_prog(jour):
     
        global cumul     # Je n'aime global, il faudra trouver comment s'en débarasser après.
     
        # Fonction pour mettre à jour l'étiquette
        def update_text(new_text):
            label1_vc.set(f"Nous sommes {jour}.")
            label2_vc.set(new_text)
     
        root.after(cumul, update_text, "Allumage de l'aquarium")
        cumul = cumul + 2000       # Les valleurs ajoutées (intervalles) seront des variables rassemblées dans un tableau
     
        # Les poissons ne sont pas nourris les mercredis et les dimanches
        if jour == "mercredi" or jour == "dimanche":
            root.after(cumul, None)
            cumul = cumul + 2000
        else:
            root.after(cumul, update_text, "Nourrissage des poissons")
            cumul = cumul + 2000
     
        root.after(cumul, update_text, "Extinction de l'aquarium")
        cumul = cumul + 2000
     
    for i in semaine:
        aqua_prog(i)
     
    root.mainloop()
    Merci pour votre aide

  2. #2
    Membre Expert
    Avatar de MPython Alaplancha
    Homme Profil pro
    Paysan à 3 francs six sous
    Inscrit en
    Juin 2018
    Messages
    914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Paysan à 3 francs six sous
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Juin 2018
    Messages : 914
    Billets dans le blog
    7
    Par défaut
    Bonjour,
    Citation Envoyé par Yobeco Voir le message
    Cependant, mon programme ne fonctionne pas : La fenêtre ne s'ouvre qu'à la toute fin de l’exécution du programme.
    La boucle for est bloquante. Tu peux la remplacer par une approche utilisant after:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    semaine.reverse()
    def callback_jour():
        jour = semaine.pop()
        aqua_prog(jour)
        if semaine:
            root.after(10, callback_jour)
    callback_jour()
    ou bien utiliser update_idletasks():

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for i in semaine:
        aqua_prog(i)
        root.update_idletasks()

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 679
    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 679
    Par défaut
    Citation Envoyé par Yobeco Voir le message
    Cependant, mon programme ne fonctionne pas : La fenêtre ne s'ouvre qu'à la toute fin de l’exécution du programme.
    Votre code fonctionne très bien à ce détail près:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        # Les poissons ne sont pas nourris les mercredis et les dimanches
        if jour == "mercredi" or jour == "dimanche":
            root.after(cumul, None)   #!<--- ici.
            cumul = cumul + 2000
        else:
            root.after(cumul, update_text, "Nourrissage des poissons")
            cumul = cumul + 2000
    car le .after sans callback équivaut à un sleep: on attend maintenant plutôt que de ne rien faire plus tard! Et comme en plus, la dernière itération est un dimanche...
    Une correction simple serait de mettre la ligne en commentaire.

    Après revoir comment à été écrite cette condition car si c'est pour ajouter 2000 à cumul dans tous les cas, il y a sans doute des écritures plus courtes.

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

  4. #4
    Membre confirmé
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Par défaut
    Citation Envoyé par Hominidé Voir le message
    Bonjour,


    La boucle for est bloquante. Tu peux la remplacer par une approche utilisant after:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    semaine.reverse()
    def callback_jour():
        jour = semaine.pop()
        aqua_prog(jour)
        if semaine:
            root.after(10, callback_jour)
    callback_jour()
    ou bien utiliser update_idletasks():

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for i in semaine:
        aqua_prog(i)
        root.update_idletasks()
    Merci pour votre réponse.

    Effectivement la boucle 'for' est bloquante.

    Je vais étudier la solution que vous m'avez proposée. Je ne connais pas les méthodes .pop() et root.update_idletasks()

    C'est une bonne occasion d'apprendre :-)

  5. #5
    Membre confirmé
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Votre code fonctionne très bien à ce détail près:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        # Les poissons ne sont pas nourris les mercredis et les dimanches
        if jour == "mercredi" or jour == "dimanche":
            root.after(cumul, None)   #!<--- ici.
            cumul = cumul + 2000
        else:
            root.after(cumul, update_text, "Nourrissage des poissons")
            cumul = cumul + 2000
    car le .after sans callback équivaut à un sleep: on attend maintenant plutôt que de ne rien faire plus tard! Et comme en plus, la dernière itération est un dimanche...
    Une correction simple serait de mettre la ligne en commentaire.

    Après revoir comment à été écrite cette condition car si c'est pour ajouter 2000 à cumul dans tous les cas, il y a sans doute des écritures plus courtes.

    - W
    Merci pour votre aide.

    Effectivement, ça marche bien juste en commentant root.after(cumul, None)

    car le .after sans callback équivaut à un sleep: on attend maintenant plutôt que de ne rien faire plus tard!
    Une fois avoir compris ça, j'ai également pensé utiliser une fonction vide :
    Et la lancer, justement quand les poissons ne mangent pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     root.after(cumul, jeuner)
    Mais ça revient au même...

    Merci à vous

    Le problème est résolu !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] Lancement d'une fonction avec un bouton poussoir
    Par michelmich dans le forum Interfaces Graphiques
    Réponses: 2
    Dernier message: 09/10/2015, 09h27
  2. Réponses: 8
    Dernier message: 12/02/2013, 01h08
  3. Réponses: 28
    Dernier message: 17/08/2006, 15h58
  4. Une fonction avec des attributs non obligatoires
    Par YanK dans le forum Langage
    Réponses: 5
    Dernier message: 15/11/2002, 13h39

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