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 :

animation qui accélère...


Sujet :

Tkinter Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre régulier
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Décembre 2017
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2017
    Messages : 8
    Par défaut animation qui accélère...
    Bonjour,

    J'ai écrit un programme Python de déplacement de billes dans un cadre avec rebondissement sur les bords du cadre. J’ai voulu placer le nombre de billes N en paramètre pouvant être modifié par l’utilisateur ( bouton Entry). Ca marche, sauf que lorsque l’utilisateur change la valeur de N, on obtient un message d’erreur :

    Exception in Tkinter callback
    Traceback (most recent call last):
    File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/init.py", line 1699, in __call_
    return self.func(*args)
    File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/init.py", line 745, in callit
    func(*args)
    File "/Users/foccus/Desktop/Python/Code2/tes1.py", line 13, in deplace
    self.x=canvas.coords(balle[self.i])[2]
    IndexError: list index out of range
    Le programme :

    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
     
    from tkinter import *
    from random import *
     
    class bille:
        def __init__(self):
            self.i=0
            self.x=0
            self.y=0
            self.dx=0
            self.dy=0
        def deplace(self,balle):
            canvas.move(balle[self.i],self.dx,self.dy)
            self.x=canvas.coords(balle[self.i])[2]
            self.y=canvas.coords(balle[self.i])[3]
            bille.mur(self)
            tk.after(20,bille.deplace,self,balle)
     
        def mur(self):
            i=self.i
            if not(20 < self.y < 310):
                self.dy=(-1)*self.dy
            if not(20 < self.x < 470):
                self.dx=(-1)*self.dx
     
    def demarrer():
        global N,tx,ty,tdx,tdy,balle
        canvas.delete(ALL)
        EN=entree_N.get()
        N=int(EN)
        tx,ty,tdx,tdy,balle=[1]*N,[1]*N,[1]*N,[1]*N,[1]*N
        for l in range(N):
            tx[l],ty[l]=randint(30,420),randint(30,250)
            tdx[l],tdy[l]=4,4
        for i in range(N):
            balle[i]=canvas.create_oval(tx[i],ty[i],tx[i]+15,ty[i]+15,fill='red',outline='black')
        for i in range(N):
            p=bille()
            p.i=i
            p.x=tx[i]
            p.y=ty[i]
            p.dx=tdx[i]
            p.dy=tdy[i]
            p.deplace(balle)
     
    #Programme Principal
    tk=Tk()
    canvas=Canvas(tk,width = 480, height = 320 , bd=0, bg="white")
    canvas.pack()
    #Creation d'un bouton "Démarrer"
    Boutton_Demarrer=Button(tk,text="Démarrer",command=demarrer)
    Boutton_Demarrer.pack(side=LEFT)
    #Creation d'un bouton "Detruire":
    Bouton_Detruire=Button(tk, text ='Quitter', command = tk.destroy)
    #Ajouter l'affichage du bouton dans la fenêtre tk:
    Bouton_Detruire.pack(side=RIGHT)
     
     
    # Nombre de balles N
    entree_N=Entry(tk,width=3)
    entree_N.pack()
     
    #Boucle principale:
    tk.mainloop()

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Salut,

    Citation Envoyé par FOCCUS Voir le message
    Ca marche, sauf que lorsque l’utilisateur change la valeur de N, on obtient un message d’erreur :

    Exception in Tkinter callback
    ...
    IndexError: list index out of range_
    L'erreur est due à cette instruction: self.x=canvas.coords(balle[self.i])[2].
    Lorsque canvas.delete(ALL) a détruit toutes les balles, les "callbacks" lancés via
    tk.after(20, bille.deplace, self, balle) existent toujours et référencent les anciens bille et balle. balle[self.i] a garder l'identifiant d'un item qui n'existe plus et canvas.coords retourne une liste vide. Et si la liste est vide, son deuxième élément est "out of range".
    Pour regarder çà, lancer l'interpréteur Python:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> import tkinter as tk
    >>> canvas = tk.Canvas()
    >>> iid = canvas.create_oval(0, 0, 100, 100)
    >>> iid
    1
    >>> canvas.coords(iid)
    [0.0, 0.0, 100.0, 100.0]
    Juste là çà fonctionne normalement.
    Puis on détruit l'item 1:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> canvas.delete(iid)
    >>> canvas.coords(iid)
    []
    >>>
    Et voilà.

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

  3. #3
    Membre régulier
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Décembre 2017
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2017
    Messages : 8
    Par défaut
    Merci! Mais alors, comment corriger svp !

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Comment çà comment corriger?
    Vous pourriez simplement tester que la liste retournée par .coords(...) n'est pas vide avant d'essayer de piocher dedans.
    Ou bien, puisque c'est l'effet de bord des "callbacks" qui survivent au canvas.delete('ALL'), vous pourriez regarder comment les supprimer avec .after_cancel. Ce qui vous obligerait à avoir une liste de billes (et reconsidérer l'intérêt de vos autres listes "globales").
    Et partant d'une liste de billes, pourquoi ne pas avoir un seul callback qui fasse bouger tous les éléments de cette liste plutôt qu'un callback par élément.

    Ce ne sont pas les solutions à explorer qui manquent...

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

  5. #5
    Membre régulier
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Décembre 2017
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2017
    Messages : 8
    Par défaut
    Merci. J'ai corrigé par un test. J'ai pas encore le courage d'utiliser after.cancel et tout revoir

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Citation Envoyé par FOCCUS Voir le message
    J'ai pas encore le courage d'utiliser after.cancel et tout revoir
    Ah ben, combien de fois avez vous jetez vos brouillons lors de la préparation de vos devoirs de français? Il faut apprendre à refaire mieux:
    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
    from tkinter import *
    from random import *
     
    class Ball:
        def __init__(self, x, y, dx, dy):
            self.iid = canvas.create_oval(
                x, y, x + 15, y + 15,
                fill='red',
                )
            self.x = x
            self.y = y
            self.dx = dx
            self.dy = dy
     
        def move(self):
            canvas.move(self.iid, self.dx, self.dy)
            # si collision avec les bords, rebond élastique.
            self.x += self.dx
            if not(20 < self.x < 470):
                self.dx = -self.dx
            self.y += self.dy
            if not(20 < self.y < 310):
                self.dy = -self.dy
     
     
    balls = []
     
    def move_balls(delay=20):
        if balls: # s'il reste des Ball...
            for b in balls:
                b.move()
            root.after(delay, move_balls)
     
    def demarrer():
        count = int(entree.get())
        canvas.delete(ALL)
        balls[:] = [] # on vide la liste.
        for _ in range(count):
            balls.append(Ball(randint(30,420),randint(30,250), 4, 4))
        move_balls()
     
    if __name__ == '__main__':
        root = Tk()
        canvas = Canvas(root,width = 480, height = 320 , bd=0, bg="white")
        canvas.pack()
     
        Button(root,text="Démarrer",command=demarrer).pack(side=LEFT)
     
        Button(root, text ='Quitter', command = root.destroy).pack(side=RIGHT)
     
        entree = Entry(root,width=3)
        entree.pack()
        mainloop()
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. Réponses: 0
    Dernier message: 20/06/2013, 11h14
  2. Problème avec Data Collector
    Par Philippe Robert dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 08/05/2012, 09h17
  3. [SL3] Problème avec le garbage collector
    Par DarkLeon dans le forum Silverlight
    Réponses: 3
    Dernier message: 24/06/2010, 12h14
  4. Réponses: 0
    Dernier message: 02/06/2009, 14h55
  5. probleme avec le garbage collector
    Par anthonycosson dans le forum MFC
    Réponses: 1
    Dernier message: 09/05/2006, 21h42

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