Problème pour déplacer une image avec tkinter

Résolu
momo9213 Messages postés 18 Statut Membre -  
momo9213 Messages postés 18 Statut Membre -

Bonjour,

J'essaye de crée un aquarium avec des poisson en python, mais je n'arrive pas à faire bouge les poissons malgré mes nombreuses tentatives.

Merci aux personnes qui essayeront de m'aider !

# importation des bibliothèques nécessaires au projet
from tkinter import *
import tkinter
import random

# Constantes du projet
LARGEUR_F = 800
HAUTEUR_F = 600

# création de la fenêtre de dessin
fenetre = tkinter.Tk()
mon_canvas = tkinter.Canvas(fenetre, width=LARGEUR_F, height=HAUTEUR_F,
                        background='lightblue')
# affichage de la zone de dessin
mon_canvas.pack()

# stockage de l'image du poisson clown dans une variable
img_clown = tkinter.PhotoImage(file="clown_fish.png")
img_clown_inv = tkinter.PhotoImage(file="clown_fish_inv.png")
# création de la liste des images de poissons
liste_images_poissons = [img_clown, img_clown_inv]

# classe Poisson
class Poisson:
    # constructeur
    def __init__(self,xLoc,yLoc,xVel,yVel):
        self.xLoc = xLoc # entier
        self.yLoc = yLoc # entier
        self.xVel = xVel
        self.yVel = yVel
        #choix de l'image dans la liste
        image_choisie =random.choices(liste_images_poissons)
        # création de l'image dans la zone de dessin
        self.img = mon_canvas.create_image(self.xLoc,self.yLoc,
                                           image=image_choisie)
   
    # Accesseurs xLoc et yLoc  
    def getXLoc(self):
        return self.xLoc
   
    def getYLoc(self):
        return self.yLoc
   
    def getXVel(self):
        return self.xVel
   
    def getYVel(self):
        return self.yVel
    # Mutateurs xLoc et yLoc
    def setXLoc(self,x): # x est un float,
        if 0 <= x <= LARGEUR_F:
            self.xLoc = x
       
    def setYLoc(self,y): # y est un float,
        if 0 <= y <= HAUTEUR_F:
                self.yLoc = y
    def setXVel(self,w): # x est un float,
            self.xVel = w  
           
    def setYVel(self,c): # x est un float,
            self.xVel = c  
             
    def deplacement():
        mon_canvas.move(fish_clown,getlXVel,getYVel)
        fenetre.after(20,deplacement)
               
class Aquarium:
     # nom est une chaine de caractere(string),
     # listeDePoissons est de type list
     def __init__(self,nom):
         self.nom=nom
         self.listeDePoissons=[]# Liste de poissons
   
     # Accesseur:
     def getNom(self):
         return self.nom
     
     # pour ajouter un poisson de classe Poisson
     def ajouter(self,poisson):
         self.listeDePoissons.append(poisson)
   
     # pour avoir le nombre de poissons de l'aquarium
     def nbPoissons(self):
         return len(self.listeDePoissons)
     
mon_aquarium = Aquarium("L'aquarium de FlopMan :|")    
for i in range(10):
    temp_xLoc = random.randint(50,750)
    temp_yLoc = random.randint(50,550)
    temp_xVel = random.randint(5,10)
    temp_yVel = random.randint(5,10)
    mon_aquarium.ajouter(Poisson(temp_xLoc,temp_yLoctemp_yVel,temp_xVel)
     
       
#instanciation de l'aquarium
#mon_aquarium = Aquarium("L'aquarium de FlopMan :|")
#ajouts de poissons
#mon_aquarium.ajouter(Poisson(400,300))
#mon_aquarium.ajouter(Poisson(700,30))
 
       

# gestion des événements, à laisser à la fin du code
fenetre.mainloop()

9 réponses

  1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    Voici ce que je te propose

    import tkinter as tk
    from random import randint
    
    WIDTH = 800
    HEIGHT = 600
    MARGIN = 100
    FISH_FILENAME = "/home/toto/poisson.png"
    NUM_FISHES = 5
    FISH_FILENAMES= [FISH_FILENAME] * NUM_FISHES
    PERIOD = 50
    
    class MoveImageApp(tk.Tk):
        def __init__(self, period: int = PERIOD, width :int = WIDTH, height :int = HEIGHT, margin :int = MARGIN):
            super().__init__()
            self.canvas = tk.Canvas(self, width=width, height=height, background="lightblue")
            self.canvas.pack()
            self.period = period
            self.objs = list() # Could contain tk.PhotoImage, tk.Rectangle, etc.
            self.photo_images = list() # See https://stackoverflow.com/a/7775792/14851404
            self.velocities = list()
            self.width = width
            self.height = height
            self.margin = margin
        def add_image(self, filename: str, x: int = 0, y: int = 0, vx: int = 0, vy: int = 0):
            img = tk.PhotoImage(file=filename)
            x = max(x, self.margin + img.width() / 2)
            x = min(x, self.width - self.margin - img.width() / 2)
            y = max(y, self.margin + img.height() / 2)
            y = min(y, self.height - self.margin - img.width() / 2)
            self.photo_images.append(img)
            self.objs.append(self.canvas.create_image(x, y, image=img))
            self.canvas.pack()
            self.velocities.append([vx, vy])
        def move_objects(self):
            for (i, (obj, photo_image, (vx, vy))) in enumerate(zip(
                self.objs,
                self.photo_images,
                self.velocities
            )):
                self.canvas.move(obj, vx, vy)
                (x_min, y_min, x_max, y_max) = self.canvas.bbox(obj)
                if x_min < self.margin or x_max > self.width - self.margin:
                    self.velocities[i][0] = -self.velocities[i][0]
                if y_min < self.margin or y_max > self.height - self.margin:
                    self.velocities[i][1] = -self.velocities[i][1]
        def repeat_move_objects(self):
            self.move_objects()
            self.after(self.period, self.repeat_move_objects)
    
    app = MoveImageApp(PERIOD, WIDTH, HEIGHT)
    for filename in FISH_FILENAMES:
        x = randint(0, app.width)
        y = randint(0, app.height)
        vx = randint(-10, 10)
        vy = randint(-10, 10)
        app.add_image(filename, x, y, vx, vy)
    app.after(0, app.repeat_move_objects)
    app.mainloop()
    

    Le paramètre period détermine le temps (en milliseconde qu'il faut attendre avant de rafraîchir le canvas.

    On crée dans notre application un canvas dans lequel on va émuler une marge supérieure, gauche, inférieure et supérieure. Les coordonnées initiales des images insérées doivent à l'intérieure des marges, sans quoi les rebonds des images sur les marges vont faire n'importe quoi.

    À chaque mouvement (move_objects), on vérifie qu'on ne fait pas dépasser l'image des marges. On exploite pour celala hit box de l'objet qu'on déplace (voir méthode bbox). Si l'image déborde sur la marge gauche ou droite (resp inférieure ou supérieure), on renverse le vecteur vitesse horizontal (resp. vertical) que j'ai appelé vx (resp. vy). En toute rigueur ce n'est pas vraiment une vitesse (c'est le nombre relatif de pixels dont on déplace l'image), mais l'idée est là.

    Bonne chance

    1
    1. momo9213 Messages postés 18 Statut Membre
       

      Merci de votre réponse mais j'ai réussi à résoudre le problème récemment. 

      0
  2. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     

    bonjour,

    à quelle ligne de code fais-tu une tentative de bouger un poisson?

    0
    1. momo9213
       

      Bonjour 

      j’ai essayé de faire bouge un poisson à la ligne 63 ( la fonction déplacement),mais je n’ai pas réussie à faire marcher la fonction ni l’utilise dans la boucle qui est à la fin de mon code 

      0
  3. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Bonjour,

    Certes, tu as défini une fonction  deplacement() pour déplacer le poisson, mais tu ne l'appelle jamais, donc

    il ne se passe rien ...

    La ligne 92 est bancale

    0
    1. momo9213 Messages postés 18 Statut Membre
       

      Oui même ayant était defenie je n’arrive pas à l’utiliser 

      j’a bien essaye de la mettre dans la ligne 92 ou bien juste avant le .mainloop mais ça ne marche pas 

      0
  4. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    "j’a bien essaye de la mettre dans la ligne 92 "

    ce n 'est pas la position de la définition de fonction qui importe, ce qu'il faut c'est l'appeler

    Exemple d'utilisation de fonction:

    def test():
        print('hello !')
    
    #appel de la fonction:
    test()
    
    0
    1. momo9213 Messages postés 18 Statut Membre
       

      Oui mais en fin de fonction j’ai essayé de l appeler 

      donc comme ceci 

      déplacement()
      fenetre.mainloop()
      0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Et tu n'as pas de message d'erreur ?

    deplacement étant une méthode de la classe Poisson, ce n'est pas comme ça qu'on l'appelle

    A mon avis, tu devrais revoir les bases du cours Python sur les classes ...

    0
  7. momo9213 Messages postés 18 Statut Membre
     

    J’ai essayé de le faire avec des cours sur internet pourriez vous me dire comment faire mieux svp

    # importation des bibliothèques nécessaires au projet
    import tkinter
    import random
    from tkinter import *
    # Constantes du projet
    LARGEUR_F = 800
    HAUTEUR_F = 600
    
    # création de la fenêtre de dessin
    fenetre = tkinter.Tk()
    mon_canvas = tkinter.Canvas(fenetre, width=LARGEUR_F, height=HAUTEUR_F,
                            background='lightblue')
    # affichage de la zone de dessin
    mon_canvas.pack(padx=10,pady=10)
    
    # stockage de l'image du poisson clown dans une variable
    algue = tkinter.PhotoImage(file="algue.png")
    tresor = tkinter.PhotoImage(file="tresor.png")
    img_clown = tkinter.PhotoImage(file="clown_fish.png")
    img_clown_inv = tkinter.PhotoImage(file="clown_fish_inv.png")
    img_poisson_orange = tkinter.PhotoImage(file="poisson_orange.png")
    img_poisson_marron = tkinter.PhotoImage(file="poisson_marron.png")
    img_poisson_rouge = tkinter.PhotoImage(file="poisson_rouge.png")
    img_poisson_sarbi = tkinter.PhotoImage(file="poisson_sarbi.png")
    
    # création de la liste des images de poissons
    liste_images_poissons = [img_clown, img_clown_inv,img_poisson_orange,img_poisson_marron,img_poisson_rouge,]
    
    # classe Poisson
    class Poisson:
       
        # constructeur
        def __init__(self,xLoc,yLoc,xVel,yVel):
            self.xLoc = xLoc # entier
            self.yLoc = yLoc # entier
            self.xVel = xVel
            self.yVel = yVel
            #choix de l'image dans la liste
            image_choisie =random.choices(liste_images_poissons)
        
            # création de l'image dans la zone de dessin
            self.img = mon_canvas.create_image(self.xLoc,self.yLoc,
                                               image=image_choisie)
        # Accesseurs xLoc et yLoc  
        def getXLoc(self):
            return self.xLoc
       
        def getYLoc(self):
            return self.yLoc
       
        def getXVel(self):
            return self.xVel
       
        def getYVel(self):
            return self.yVel
        # Mutateurs xLoc et yLoc
        def setXLoc(self,x): # x est un float,
            if 0 <= x <= LARGEUR_F:
                self.xLoc = x
           
        def setYLoc(self,y): # y est un float,
            if 0 <= y <= HAUTEUR_F:
                    self.yLoc = y
        def setXVel(self,w): # x est un float,
                self.xVel = w  
               
        def setYVel(self,c): # x est un float,
                self.xVel = c  
                   
               
                   
        def affiche(self):
            self.move(self,self.xVel,self.yVel)
    
     # move de l'image dans la zone de dessin
        def deplacement(self,poisson):
            fenetre.after(20,deplacement)
                   
    class Aquarium:
         # nom est une chaine de caractere(string),
         # listeDePoissons est de type list
         def __init__(self,nom):
             self.nom=nom
             self.listeDePoissons=[]# Liste de poissons
       
         # Accesseur:
         def getNom(self):
             return self.nom
         
         # pour ajouter un poisson de classe Poisson
         def ajouter(self,poisson):
             self.listeDePoissons.append(poisson)
       
         # pour avoir le nombre de poissons de l'aquarium
         def nbPoissons(self):
             return len(self.listeDePoissons)
         
    mon_aquarium = Aquarium("aquarium")    
    for i in range(10):
        temp_xLoc = random.randint(50,750)
        temp_yLoc = random.randint(50,550)
        temp_xVel = random.randint(5,10)
        temp_yVel = random.randint(5,10)
        mon_aquarium.ajouter(Poisson(temp_xLoc,temp_yLoc,temp_yVel,temp_xVel))
    
    def fonction_principale():
        for i in range(mon_aquarium.nbPoissons()):
            mon_aquaruim.listeDePoissons[i].deplacement()
            mon_aquarim.listeDePoissons[i].affiche()
            mon_canvas.after(100,fonction_principale)
            fonction_principale()
    
    # gestion des événements, à laisser à la fin du code
    
    fenetre.mainloop()
    
    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      Pourquoi ne fais-tu pas d'abord des exercices plus simples avec tkinter?  Cela te permettra de comprendre les bases et de progresser.

      0
  8. momo9213 Messages postés 18 Statut Membre
     

    Je n’arrive pas à faire les exercices 

    j’ai essayé de faire celui ci avec le coût qu’il y a avec mais c’est pareil 

    http://tableauxmaths.fr/spip/spip.php?article48

    0
  9. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    ou alors, tu essaie déjà avec un poisson et sans utiliser de classes:

    définition de la fonction deplace()

    (la fonction mon_canvas.move() déplace l'objet img avec des valeurs de déplacement en xy, par exemple 10,-10)

    création de la fenêtre principale

    création du Canvas

    stockage d'une image : img = tkinter.PhotoImage(.....)

    affichage de img dans le canvas

    appel de deplace()

    mainloop()

    0
  10. momo9213 Messages postés 18 Statut Membre
     

    j'ai essaye ceci mais ca ne marche point 

    # importation des bibliothèques nécessaires au projet
    import tkinter
    # Constantes du projet
    LARGEUR_F = 800
    HAUTEUR_F = 600
    
    # création de la fenêtre de dessin
    fenetre = tkinter.Tk()
    mon_canvas = tkinter.Canvas(fenetre, width=LARGEUR_F, height=HAUTEUR_F,
                            background='lightblue')
    # affichage de la zone de dessin
    mon_canvas.pack(padx=10,pady=10)
    
    
    img_clown = tkinter.PhotoImage(file="clown_fish.png")
    mon_canvas.create_image(700,550,image=img_clown)
    
    def deplacement():
        mon_canvas.move(img_clown,10,10)
        fenetre.after(20,deplacement)
                   
    
    
    # gestion des événements, à laisser à la fin du code
    deplacement()
    fenetre.mainloop()
    
    0
    1. voji
       

      Bonjour, ce que tu dois déplacer, c'est l'image, de plus 20 ms, c'est bien trop rapide pour tester.

      img_clown = tkinter.PhotoImage(file="clown_fish.png")
      id_image_clown = mon_canvas.create_image(700,550,image=img_clown)
      
      def deplacement():
          mon_canvas.move(id_image_clown, 10, 10)
          fenetre.after(200, deplacement)
      0
    2. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
       

      Bonjour,

      Déjà, tu places ton image en bas de la fenêtre (700,550), et en plus, tu la déplaces

      vers le bas (y positif : 10,10)

      Ensuite, ce n'est pas 

       fenetre.after(200, deplacement)

      Mais 

      mon_canvas.after(200,deplacement)

      Et enfin, ce n'est pas img_clown qu'il faut déplacer, c'est l'objet créé par:

      img = mon_canvas.create_image(70,55,image=img_clown)

      donc 

      mon_canvas.move(img,100,100)
      0
    3. momo9213 Messages postés 18 Statut Membre > voji
       

      merci je pense enfin avoir compris mon erreur 

      0
    4. momo9213 Messages postés 18 Statut Membre > Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention  
       

      je vous remercie, j'ai compris mon erreur 

      0
    5. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588 > momo9213 Messages postés 18 Statut Membre
       

      Peux-tu alors marquer la discussion comme résolue?

      0