Tkinter Méthode Delete - Problème avec POO

Signaler
-
Messages postés
351
Date d'inscription
lundi 23 mars 2020
Statut
Membre
Dernière intervention
6 septembre 2020
-
Bonjour,

Je commence à appréhender Python et les interfaces graphiques en me forçant à me mettre dans une logique POO.

Dans le but de m'entraîner aux interactions entre classes, j'ai créé ce petit programme très simple, pour faire grossir et diminuer une balle dans un canevas.

Mais par souci d'optimisation, je me doute que la ligne 30 (et 37) n'est pas la plus adaptée. Car s'il y a un autre objet que je souhaitais laisser intact dans le canevas, il serait également effacé. Comment puis-je donc faire pour que l'objet qui appelle la méthode "increase" ou "decrease" s'efface lui-même. En bref par quoi remplacer l'argument "ALL" pour être sélectif sur l'objet concerné?
J'ai tenté de remplacer par self.can.delete(self) mais ça ne fonctionne pas..
J'ai aussi essayé en faisant self.can.delete(self.ball1) mais ça me renvoie une erreur
Je me suis documenté, mais je ne trouve pas de réponse..

Merci beaucoup pour votre aide


# Une balle grossit et diminue dans un canevas

class Application(object):  
    
    def __init__(self):
        """Constructeur de la fenêtre principale et du canevas"""
        self.fen=Tk()
        self.can=Canvas(self.fen, width=500, height=500, bg='dark red')
        self.can.pack()  
        self.ball1 = Ball(self.can) # Instanciation d'une balle
        self.fen.bind("<Up>",self.ball1.increase)
        self.fen.bind("<Down>",self.ball1.decrease)
        self.fen.mainloop()

class Ball(object):
    "Classe des balles"
    def __init__(self, canevas, x=250, y=250, r=10, color='white'):
        self.can = canevas
        self.x = x
        self.y = y
        self.r = r
        self.fill= color
        self.outline= 'black'
        self.can.create_oval(x-r,y-r,x+r,y+r,fill=self.fill, outline=self.outline)
    
    def increase(self,event):
        "Méthode pour faire grossir la balle avec un appui de touche"
        self.r +=10  # La méthode incrémente le rayon
        #La méthode doit effacer l'objet existant qui appelle la méthode
        self.can.delete(ALL) 
        #La méthode doit maintenant le recréer
        self.can.create_oval(self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r,fill=self.fill, outline=self.outline)
    
    def decrease(self,event):
        "Méthode pour faire diminuer la balle avec un appui de touche"
        self.r -=10
        self.can.delete(ALL)
        self.can.create_oval(self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r,fill=self.fill, outline=self.outline)

# Programme Principal

if __name__=='__main__':
    from tkinter import *
    f = Application()  # Instanciation de l'objet application

6 réponses

Messages postés
351
Date d'inscription
lundi 23 mars 2020
Statut
Membre
Dernière intervention
6 septembre 2020
57
Bonsoir Laxfiskar,

Oui, n'efface pas l'objet pour le redessiner, mais met plutôt à jour ses coordonnées
Exemple avec increase:

        ..........
        self.oval = self.can.create_oval(x-r,y-r,x+r,y+r,fill=self.fill, outline=self.outline)
    
    def increase(self,event):
        "Méthode pour faire grossir la balle avec un appui de touche"
        self.r +=10  # La méthode incrémente le rayon
        self.can.coords(self.oval, self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r)
    ...................


Il y a déjà moins de lignes de code :-)
Super ça fonctionne!
Si je comprends bien, mon erreur était de ne pas avoir stocké la création du cercle dans une variable. Et donc, impossible d'y faire référence par la suite avec la méthode delete ou coords.

Merci beaucoup pour ton éclairage!
Messages postés
351
Date d'inscription
lundi 23 mars 2020
Statut
Membre
Dernière intervention
6 septembre 2020
57
C'est parfois utile de donner un nom aux objets que l'on créé

A noter que la méthode coords fonctionne avec toute sorte d'objets ...

Ca aussi peut servir à déplacer la balle, par exemple
Merci beaucoup!

J'en profite, car j'ai une deuxième question sur un sujet un peu similaire, mais qui concerne cette fois la méthode AFTER avec Tkinter.
J'essaie tout simplement l'exercice d'animation automatique d'une balle, que je comprends bien en version procédurale, mais ici je coince un peu quand je transforme en version objet.

Le noeud se trouve selon moi à la ligne 41, quand ma fonction anime() doit appeler la fonction after avant de se relancer. (Je souhaite simplement créer une boucle qui s'interrompra plus tard quand la variable flag passera à 0 - partie de code non encore écrite).

Je me rends bien compte que self.fen.after est incorrect car la classe Ball n'a pas de méthode after.. Idem pour self.fen.. Mais comment faire référence à la fenêtre pour que cela fonctionne?

Merci beaucoup pour votre aide

Le code est:

# Code pour créer une balle animée dans le canevas

class Application(object):
    "Classe de création de l'application"
    def __init__(self):
        
        #Création de la fenêtre
        self.fen = Tk()
        self.fen.title('Jeu de la balle')
        
        #Création du canevas
        self.can=Canvas(height=500, width=500, bg='aliceblue')
        self.can.pack()
        
        #Instanciation d'un objet de la classe Ball
        ball1=Ball(self.can, 200, 200, 30, 'lightskyblue')
        
        #Mise en mouvement de la balle
        ball1.anime()
        
        # Mise en alerte de la fenetre
        self.fen.mainloop()
        
class Ball(object):
    "Classe de création d'une balle"
    def __init__(self, canevas, x=100, y=100, r=20, color='white'):
        self.can = canevas
        self.x = x
        self.y = y
        self.r = r
        self.color = color
        self.flag = 1
        self.oval = self.can.create_oval(self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r,fill=self.color)
    
    def anime(self):
        self.x += 5
        print(self.x)
        self.y += 5
        self.can.coords(self.oval,self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r)
        if self.flag==1:
            self.fen.after(100,ball1.anime)
            self.anime()


#----PROGRAMME PRINCIPAL-----
if __name__=='__main__':
    from tkinter import *
    f=Application()
J'ai trouvé la cause.. Je ne passais pas self.fen en paramètre au moment de l'instanciation de l'objet ball1. Donc cet objet ne pouvait pas être appelé.

Voici mon auto-correction:

# Code pour créer une balle animée dans le canevas
# Attention, il faut bien passer la fenetre en parametres!

class Application(object):
    "Classe de création de l'application"
    def __init__(self):
        
        #Création de la fenêtre
        self.fen = Tk()
        self.fen.title('Jeu de la balle')
        
        #Création du canevas
        self.can=Canvas(height=500, width=500, bg='aliceblue')
        self.can.pack()
        
        #Instanciation d'un objet de la classe Ball
        ball1=Ball(self.fen, self.can, 200, 200, 30, 'lightskyblue')
        
        #Mise en mouvement de la balle
        ball1.anime()
        
        # Mise en alerte de la fenetre
        self.fen.mainloop()   
            
class Ball(object):
    "Classe de création d'une balle"
    def __init__(self, fenetre, canevas, x=100, y=100, r=20, color='white'):
        self.fen = fenetre
        self.can = canevas
        self.x = x
        self.y = y
        self.r = r
        self.color = color
        self.flag = 1
        self.oval = self.can.create_oval(self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r,fill=self.color)
    
    def anime(self):
        self.x += 5
        print(self.x)
        self.y += 5
        self.can.coords(self.oval,self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r)
        if self.flag >0:
            self.fen.after(10,self.anime)

#----PROGRAMME PRINCIPAL-----
if __name__=='__main__':
    from tkinter import *
    f=Application()
Messages postés
351
Date d'inscription
lundi 23 mars 2020
Statut
Membre
Dernière intervention
6 septembre 2020
57
Bonjour Laxfiskar,

OK, donc tout va bien maintenant ...