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 :

message d'erreur à la fermeture


Sujet :

Tkinter Python

  1. #1
    Membre chevronné
    Avatar de Archimède
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2005
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 644
    Points : 1 975
    Points
    1 975
    Par défaut message d'erreur à la fermeture
    Comment éviter le message d'erreur à la fermeture sur cet exemple simple :

    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
     
    import tkinter as tk
    ok=True
     
    def incremente():
        global compteur
        compteur += 1
        compteur_lbl['text'] = str(compteur)
        if ok:
            app.after(1000, incremente)
     
     
     
    app = tk.Tk()
    compteur = 0
     
    compteur_lbl = tk.Label(app, text=str(compteur), font=("", 16))
    compteur_lbl.grid(padx=8, pady=8)
    app.after(1000, incremente)
     
     
    def quitter():
        global ok
        ok=False
        app.destroy()
     
     
    app.protocol('WM_DELETE_WINDOW', quitter)
    app.mainloop()
    message dans mu-editor :
    >>> invalid command name "2195026287624incremente"
    while executing
    "2195026287624incremente"
    ("after" script)
    Merci (j'ai le même problème avec l'utilisation d'un thread pour le timer...)

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

    Vous comprenez ce que raconte l'erreur? Si le Label a été détruit, lorsque la fonction déclenchée par .after essaie de le mettre à jour... erreur.

    Après la question est de savoir pourquoi le bidouillage que vous avez fabriqué avec la variable OK ne fonctionne pas.
    Relisez votre code: la variable ne contrôle que l'instruction .after i.e. l’ordonnancement d'une opération qui se déclenchera dans une seconde (que l'application ait été détruite ou pas d'ici là).

    note: jetez aussi un œil à after_cancel

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

  3. #3
    Membre chevronné
    Avatar de Archimède
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2005
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 644
    Points : 1 975
    Points
    1 975
    Par défaut
    Salut,

    j'avais déjà testé la méthode after_cancel(id), sans succès... Il fallait déclarer timer en global dans la procédure appelée chaque seconde :
    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
     
    import tkinter as tk
     
    def incremente():
        global compteur
        global timer  # ici  sinon ça plante avec mu et pas sous pyzo....  L'encapsulation est étrange en python... l'instruction global n'est pas la + heureuse.
        compteur += 1
        compteur_lbl['text'] = str(compteur)
        timer=app.after(1000, incremente)
     
    app = tk.Tk()
    compteur = 0
     
    compteur_lbl = tk.Label(app, text=str(compteur), font=("", 16))
    compteur_lbl.grid(padx=8, pady=8)
    timer=app.after(1000, incremente)
     
     
     
    def quitter():
        app.after_cancel(timer)
        app.destroy()
     
     
    app.protocol('WM_DELETE_WINDOW', quitter)
    app.mainloop()

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

    Citation Envoyé par Archimède Voir le message
    j'avais déjà testé la méthode after_cancel(id), sans succès... Il fallait déclarer timer en global dans la procédure appelée chaque seconde.
    Alors problème résolu?

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

  5. #5
    Membre chevronné
    Avatar de Archimède
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2005
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 644
    Points : 1 975
    Points
    1 975
    Par défaut
    Oui, excuse...
    J'avais déjà testé after_cancel(id) sur mon code qui posait problème mais je l'utilisais sur un objet d'une classe qui dérivait de canvas....
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    monobjet.after_cancel(timer)
    et j'avais un message d'erreur à la fermeture de l'application...
    En faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fen .after_cancel(timer)
    au lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    monObjet.after_cancel(timer)
    , plus de problème... et le dans la procédure appelée à chaque intervaltimer qui fait aussi planter sous mu-editor si pas déclaré...
    Si ça peut servir pour un autre...

    A+ et merci encore

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

    Vous devez être "cohérent" avec le widget utilisé pour soumettre les .after et celui utilisé pour .after_cancel.

    Dérrière .after, il y a la création d'une variable Tk associée à l'objet qui réalise le callback a appeler. Cette variable (Tk) est l'identifiant retourné par .after, il est "global".
    Mais l'objet à appeler est stocké côté widget.

    .after_cancel appliqué à n'importe quel autre widget (que celui utilisé pour .after) va supprimer le côté Tk, mais ne change pas le côté tkinter. Lorsque destroy fait le ménage, il demande à Tk de détruire quelque chose qui n'existe plus.
    Exemple:
    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 as tk
    >>> root = tk.Tk()
    >>> w = tk.Label()
    >>> z = tk.Label()
    >>> w.after(10000, print, 'toto')
    'after#0'
    >>> z.after_cancel('after#0')
    >>> w.destroy()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\py_env\py64_38\lib\tkinter\__init__.py", line 2578, in destroy
        Misc.destroy(self)
      File "C:\py_env\py64_38\lib\tkinter\__init__.py", line 630, in destroy
        self.tk.deletecommand(name)
    _tkinter.TclError: can't delete Tcl command
    Par contre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> w = tk.Label()
    >>> w.after(10000, print, 'toto')
    'after#1'
    >>> w.after_cancel('after#1')
    >>> w.destroy()
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre chevronné
    Avatar de Archimède
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2005
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 644
    Points : 1 975
    Points
    1 975
    Par défaut
    Salut,

    dans le Callback, si tu ne mets pas global à l'identifiant, ça plante à la fermeture avec mu-editor... et avec pyzo, ça passe ?
    Donc, l'identifiant est global comme tu as l'air de l'affirmer ou pas ?
    Un bug de mu-editor ?
    Deuxième exemple pris sur le web et adapté à la fermeture :
    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
     
    from tkinter import *
     
    SIDE=400
    PAD=SIDE//12
    dx,dy=2,2
     
    def move():
        global dx
        global dy
        #global timer
        ulx, uly, lrx, lry = list(map(int, cvs.coords(ball)))
        # bords verticaux
        if ulx <=0 or lrx >=SIDE:
            dx=-dx
        # bords horizontaux
        elif uly<=0 or lry>=SIDE:
            dy=-dy
        cvs.move(ball, dx, dy)
        timer=cvs.after(20, move)
     
    # Création d’un canevas
    w=Tk()
    cvs=Canvas(w, width=SIDE, height=SIDE, highlightthickness=0,
    bg="ivory")
    cvs.pack(padx=PAD, pady=PAD)
     
    # Création d’une balle
    R=20
    x0=200
    y0=40
    ball=cvs.create_oval(x0, y0, 2*R+x0, 2*R+y0, outline='#ff0000',
    fill='#ff0000')
     
     # Lancement de l’animation
    timer=cvs.after(20, move)
     
     
    def quitter():
        cvs.after_cancel(timer)
        w.destroy()
     
    w.protocol('WM_DELETE_WINDOW', quitter)
     
    w.mainloop()
    >>> invalid command name "1902049716744move"
    while executing
    "1902049716744move"
    ("after" script)
    Et si je mets timer en global dans le callback, plus de problème à la fermeture dans mu..
    >>>
    C'est curieux, cette différence de comportement entre pyzo et mu...

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

    Vu que les IDE n'exécutent pas les scripts dans un environnement "normal" mais de "debug", en cas de soucis, il faut toujours le confirmer avec une exécution "normale".

    Citation Envoyé par Archimède Voir le message
    Donc, l'identifiant est global comme tu as l'air de l'affirmer ou pas ?
    invalid command name "1902049716744move" est un message d'erreur Tk rapporté par tkinter (2 choses différentes). "1902049716744move" est une variable Tk qui n'a rien à voir avec une variable Python.

    Après relisez votre code, si dans move la variable timer n'est pas global, elle ne sera pas mise à jour par les appels successifs à .after.

    Et le callback quitter va récupérer à travers timer le nom de la commande Tk crée par le premier .after.
    Commande détruite dès la première exécution de move.
    C'est juste ce que dit le message d'erreur dans ce cas.

    Après pourquoi vous voyez l'erreur dans un IDE et pas dans l'autre? Comme ce ne sont pas des environnements d'exécution "normaux"...

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

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

Discussions similaires

  1. Message d'erreur à la fermeture d'une fenêtre
    Par Pascal Lob dans le forum VB.NET
    Réponses: 5
    Dernier message: 16/11/2011, 11h20
  2. Message d'erreur à la fermeture de la base
    Par theuma dans le forum Runtime
    Réponses: 4
    Dernier message: 16/06/2011, 08h21
  3. message d'erreur à la fermeture
    Par nefertari dans le forum Delphi
    Réponses: 10
    Dernier message: 12/07/2007, 07h25
  4. Message d'erreur à la fermeture d'une page web
    Par WELCOMSMAIL dans le forum Autres Logiciels
    Réponses: 2
    Dernier message: 26/04/2006, 17h12

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