Partage
  • Partager sur Facebook
  • Partager sur Twitter

Déplacer un objet de 100px ... et que ça se "voie"

    14 janvier 2023 à 9:21:24

    EDIT : j'ai trouvé à peu près comment faire, voir en bas du sujet, mais j'en encore une question.

    Bonjour,

    Après de nombreux essais de méthode, je ne parviens pas à déplacer un objet.

    Je souhaiterais déplacer un objet de 100px vers la droite.

    J'ai donc créé cette fonction :

    def deplacement(objet,dx):
            print(objet)
            print(dx)
            for i in range(10):
                zone_princ.move(objet, dx, 0)
                time.sleep(0.1)

    que j'appelle ici (je teste avec un objet taggué "millier").

    def casse(objet,compteur):
        global milliers,centaines,dizaines,unites, objets_milliers, nombre, m,c,d,u
        if compteur>0:
            compteur=compteur-1
            if objet=="millier":
                deplacement((objets_milliers[-1]),10)
                milliers=milliers-1
                m=m-1
                nombre=nombre-1000
                zone_princ.delete(objets_milliers[-1])
                objets_milliers.pop()
                for i in range(10):
                    cree("centaine", img_centaine,100)
            if objet=="centaine":
                centaines=centaines-1
                nombre=nombre-100
                c=c-1
                zone_princ.delete(objets_centaines[-1])
                objets_centaines.pop()
                for i in range(10):
                    cree("dizaine", img_dizaine,10)
            if objet=="dizaine":
                dizaines=dizaines-1
                nombre=nombre-10
                d=d-1
                zone_princ.delete(objets_dizaines[-1])
                objets_dizaines.pop()
                for i in range(10):
                    cree("unite", img_unite,1)
    


    Pour être sûr que la fonction tourne, j'ai mis :

            print(objet)
            print(dx)

    qui renvoie bien :

    5 (soit l'identifiant de l'objet, en effet c'est bien lui).

    10 (la valeur de dx)

    Il y a bien une seconde de pause, donc 10x 0.1 seconde.

    Mais ... ça ne bouge pas.

    Si j'affiche en print les coordonnées de l'objet à chaque itération, je la vois bien progresser de 10 à chaque fois ... mais on ne voit rien graphiquement !

    Comment faire ? J'ai vu des solutions avec canvas.after, mais du coup ça fait une boucle infinie, or je n'ai besoin que d'un déplacement court et borné.

    Merci

    Le code complet 🔽

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    from tkinter import *
    from random import *
    import time
    
    #Création de la fenêtre
    
    fenetre = Tk()
    larg=fenetre.winfo_screenwidth()-100
    haut=fenetre.winfo_screenheight()-100
    fenetre.title("Numération")
    fenetre.geometry(f"{larg}x{haut}+0+0")
    
    #Cré"ation des cadres
    zone_haut=Frame(fenetre, height=100, relief="sunken").grid(row=0,column=0)
    zone_gauche=Frame(fenetre, width=100, height=haut-100, relief="raised").grid(row=1,column=0)
    zone_princ=Canvas(fenetre, width=larg-100, height=haut-100, bg="#d6e2e4")
    zone_princ.grid(row=1,column=1)
    
    #Variables
    
    larg_canvas=larg-100
    haut_canvas=haut-100
    marge=50
    larg_colonne=(larg_canvas-(5*marge))/4
    posx=posy=marge
    tagobjet=0
    nombre=0
    milliers=centaines=dizaines=unites=0
    m=c=d=u=1
    
    #Création des zones milliers, centaines, dizaines, unités
    
    for i in ("milliers","centaines","dizaines","unites"):
        i=zone_princ.create_rectangle(posx,posy,larg_colonne+posx,haut_canvas-marge, fill="#d9dce6", tags=f"{i}")
        posx=posx+marge+larg_colonne
    
    #Création de listes des coordonnées des coins des rectangles
    
    liste_millier=zone_princ.coords("milliers")
    liste_centaine=zone_princ.coords("centaines")
    liste_dizaine=zone_princ.coords("dizaines")
    liste_unite=zone_princ.coords("unites")
    
    objets_milliers=[]
    objets_centaines=[]
    objets_dizaines=[]
    objets_unites=[]
    
    #Déclaration des images
    
    img_unite=PhotoImage(file="images/unite.png")
    img_unite_select=PhotoImage(file="images/unite_select.png")
    img_dizaine=PhotoImage(file="images/dizaine.png")
    img_dizaine_select=PhotoImage(file="images/dizaine_select.png")
    img_centaine=PhotoImage(file="images/centaine.png")
    img_centaine_select=PhotoImage(file="images/centaine_select.png")
    img_millier=PhotoImage(file="images/millier.png")
    img_millier_select=PhotoImage(file="images/millier_select.png")
    
    
    
    #Pour afficher en console le nombre total et le nombre de chaque puissance de 10
    def console():
        print(nombre)
        print(f'{milliers} milliers')
        print(f'{centaines} centaines')
        print(f'{dizaines} dizaines')
        print(f'{unites} unités')
    
    #Boucle de création d'une image
    
    def cree(objet,img,valeur):
        global nombre, milliers, centaines, dizaines, unites,u,d,c,m
        #On incrémente les compteur
        nombre=nombre+valeur
        #On récupère les coordonnées de la colonne correspondante et on incrémente le nombre de chaque
        if objet=="millier":
            liste_coords=liste_millier
            milliers=milliers+1
        if objet=="centaine":
            liste_coords=liste_centaine
            centaines=centaines+1
        if objet=="dizaine":
            liste_coords=liste_dizaine
            dizaines=dizaines+1
        if objet=="unite":
            liste_coords=liste_unite
            unites=unites+1
        #affichages en console
        maj()
    
        #On attribue des positions maxi
        x1=int(liste_coords[0]+60)
        x2=int(liste_coords[2]-60)
        y1=int(liste_coords[1]+60)
        y2=int(liste_coords[3]-60)
        #On crée l'objet à une position aléatoire à l'intérieur des positions maxi et on le taggue avec le type d'objet
        if objet=="millier":
            objets_milliers.append(zone_princ.create_image(randint(x1,x2), randint(y1,y2), image=img, tags=objet))
            m=1
        if objet=="centaine":
            objets_centaines.append(zone_princ.create_image(randint(x1,x2), randint(y1,y2), image=img, tags=objet))
            c=1
        if objet=="dizaine":
            objets_dizaines.append(zone_princ.create_image(randint(x1,x2), randint(y1,y2), image=img, tags=objet))
            d=1
        if objet=="unite":
            objets_unites.append(zone_princ.create_image(randint(x1,x2), randint(y1,y2), image=img, tags=objet))
            u=1
    
    
    def maj():
        compteur.configure(text=nombre)
        compteur_milliers.configure(text=milliers)
        compteur_centaines.configure(text=centaines)
        compteur_dizaines.configure(text=dizaines)
        compteur_unites.configure(text=unites)
    
    def suppr(objet):
        global nombre, milliers, centaines, dizaines, unites, u,d,c,m
        if objet=="millier":
            milliers = milliers - 1
            m = m - 1
            nombre = nombre - 1000
            zone_princ.delete(objets_milliers[-1])
            objets_milliers.pop()
        if objet=="centaine":
            centaines = centaines - 1
            nombre = nombre - 100
            c = c - 1
            zone_princ.delete(objets_centaines[-1])
            objets_centaines.pop()
        if objet=="dizaine":
            dizaines = dizaines - 1
            nombre = nombre - 10
            d = d - 1
            zone_princ.delete(objets_dizaines[-1])
            objets_dizaines.pop()
        if objet=="unite":
            unites= unites - 1
            nombre = nombre - 1
            u = u - 1
            zone_princ.delete(objets_unites[-1])
            objets_unites.pop()
        nombre=1000*milliers+100*centaines+10*dizaines+unites
        maj()
    
    def reset(objet):
        global nombre, milliers, centaines, dizaines, unites
        if objet=="millier":
            zone_princ.delete("millier")
            milliers=0
        if objet=="centaine":
            zone_princ.delete("centaine")
            centaines=0
        if objet=="dizaine":
            zone_princ.delete("dizaine")
            dizaines=0
        if objet=="unite":
            zone_princ.delete("unite")
            unites=0
        nombre=1000*milliers+100*centaines+10*dizaines+unites
        maj()
    
    
    def deplacement(objet,dx):
            print(objet)
            print(dx)
            for i in range(10):
                zone_princ.move(objet, dx, 0)
                time.sleep(0.1)
    
    
    def casse(objet,compteur):
        global milliers,centaines,dizaines,unites, objets_milliers, nombre, m,c,d,u
        if compteur>0:
            compteur=compteur-1
            if objet=="millier":
                deplacement((objets_milliers[-1]),10)
                milliers=milliers-1
                m=m-1
                nombre=nombre-1000
                zone_princ.delete(objets_milliers[-1])
                objets_milliers.pop()
                for i in range(10):
                    cree("centaine", img_centaine,100)
            if objet=="centaine":
                centaines=centaines-1
                nombre=nombre-100
                c=c-1
                zone_princ.delete(objets_centaines[-1])
                objets_centaines.pop()
                for i in range(10):
                    cree("dizaine", img_dizaine,10)
            if objet=="dizaine":
                dizaines=dizaines-1
                nombre=nombre-10
                d=d-1
                zone_princ.delete(objets_dizaines[-1])
                objets_dizaines.pop()
                for i in range(10):
                    cree("unite", img_unite,1)
    
    
    def groupe(objet,compteur):
        global milliers,centaines,dizaines,unites, objets_milliers, nombre,u,d,c,m, dx, dy
        dx=-10
        dy=0
        if compteur>=10:
            compteur=compteur+10
            if objet=="unite" and u-1==10:
                unites=unites-10
                u=u-10
                nombre=nombre-10
                for i in range (10):
                    zone_princ.delete(objets_unites[-1])
                    objets_unites.pop()
                cree("dizaine", img_dizaine,10)
            if objet=="dizaine" and d-1==10:
                dizaines=dizaines-10
                d=d-10
                nombre=nombre-100
                for i in range(10):
                    zone_princ.delete(objets_dizaines[-1])
                    objets_dizaines.pop()
                cree("centaine", img_centaine,100)
            if objet=="centaine" and c-1==10:
                centaines=centaines-10
                c=c-10
                nombre=nombre-1000
                for i in range(10):
                    zone_princ.delete(objets_centaines[-1])
                    objets_centaines.pop()
                cree("millier", img_millier,1000)
    
    
    def select(objet):
        global m,c,d,u,unites,dizaines,centaines,milliers
        if objet=="unite" and unites>0 and u<=len(objets_unites):
            zone_princ.itemconfig((objets_unites[-u]),image=img_unite_select)
            u=u+1
        if objet=="dizaine" and dizaines>0 and d<=len(objets_dizaines):
            zone_princ.itemconfig((objets_dizaines[-d]),image=img_dizaine_select)
            d=d+1
        if objet=="centaine" and centaines>0 and c<=len(objets_centaines):
            zone_princ.itemconfig((objets_centaines[-c]),image=img_centaine_select)
            c=c+1
        if objet=="millier" and milliers>0 and m<=len(objets_centaines):
            zone_princ.itemconfig((objets_milliers[-m]),image=img_millier_select)
            m=m+1
    
    def deselect(objet):
        global m,c,d,u,unites,dizaines,centaines,milliers
        if objet=="unite" and unites>0 and u>0:
            zone_princ.itemconfig((objets_unites[1-u]),image=img_unite)
            u=u-1
        if objet=="dizaine" and dizaines>0 and d>0:
            zone_princ.itemconfig((objets_dizaines[1-d]),image=img_dizaine)
            d=d-1
        if objet=="centaine" and centaines>0 and c>0:
            zone_princ.itemconfig((objets_centaines[1-c]),image=img_centaine)
            c=c-1
        if objet=="millier" and milliers>0 and m>0:
            zone_princ.itemconfig((objets_milliers[1-m]),image=img_millier)
            m=m-1
    
    
    
    #Compteurs
    
    compteur=Label(zone_gauche, text=nombre)
    compteur.grid(row=0,column=0)
    
    compteur_milliers=Label(zone_haut, text=milliers)
    compteur_centaines=Label(zone_haut, text=centaines)
    compteur_dizaines=Label(zone_haut, text=dizaines)
    compteur_unites=Label(zone_haut, text=unites)
    
    compteur_milliers.place(x = (liste_millier[0]+liste_millier[2])/2+100, y = 80, anchor=CENTER)
    compteur_centaines.place(x = (liste_centaine[0]+liste_centaine[2])/2+100, y = 80, anchor=CENTER)
    compteur_dizaines.place(x = (liste_dizaine[0]+liste_dizaine[2])/2+100, y = 80, anchor=CENTER)
    compteur_unites.place(x = (liste_unite[0]+liste_unite[2])/2+100, y = 80, anchor=CENTER)
    
    #Boutons
    
    reset_millier=Button(zone_haut, text="reset milliers", command=lambda:reset("millier"))
    reset_centaine=Button(zone_haut, text="reset centaines", command=lambda:reset("centaine"))
    reset_dizaine=Button(zone_haut, text="reset dizaines", command=lambda:reset("dizaine"))
    reset_unite=Button(zone_haut, text="reset unités", command=lambda:reset("unite"))
    
    reset_millier.place(x = (liste_millier[0]+liste_millier[2])/2+100, y = 50, anchor=CENTER)
    reset_centaine.place(x = (liste_centaine[0]+liste_centaine[2])/2+100, y = 50, anchor=CENTER)
    reset_dizaine.place(x = (liste_dizaine[0]+liste_dizaine[2])/2+100, y = 50, anchor=CENTER)
    reset_unite.place(x = (liste_unite[0]+liste_unite[2])/2+100, y = 50, anchor=CENTER)
    
    casse_millier=Button(zone_princ, text=">>>", command=lambda:casse("millier",milliers))
    casse_centaine=Button(zone_princ, text=">>>", command=lambda:casse("centaine",centaines))
    casse_dizaine=Button(zone_princ, text=">>>", command=lambda:casse("dizaine",dizaines))
    groupe_unites=Button(zone_princ, text="<<<", command=lambda:groupe("unite",unites))
    groupe_dizaines=Button(zone_princ, text="<<<", command=lambda:groupe("dizaine",dizaines))
    groupe_centaines=Button(zone_princ, text="<<<", command=lambda:groupe("centaine",centaines))
    
    
    casse_millier.place(x=(liste_millier[0]+liste_millier[2])/2,y=haut_canvas-marge/2, anchor=CENTER)
    casse_centaine.place(x=(liste_centaine[0]+liste_centaine[2])/2,y=haut_canvas-marge/2, anchor=W)
    casse_dizaine.place(x=(liste_dizaine[0]+liste_dizaine[2])/2,y=haut_canvas-marge/2, anchor=W)
    groupe_centaines.place(x=(liste_centaine[0]+liste_centaine[2])/2,y=haut_canvas-marge/2, anchor=E)
    groupe_dizaines.place(x=(liste_dizaine[0]+liste_dizaine[2])/2,y=haut_canvas-marge/2, anchor=E)
    groupe_unites.place(x=(liste_unite[0]+liste_unite[2])/2,y=haut_canvas-marge/2, anchor=CENTER)
    
    
    select_unite=Button(zone_princ, text="✅", command=lambda: select("unite"),background="red", fg="white")
    select_dizaine=Button(zone_princ, text="✅", command=lambda: select("dizaine"),background="red")
    select_centaine=Button(zone_princ, text="✅", command=lambda: select("centaine"),background="red")
    deselect_unite=Button(zone_princ, text="✅", command=lambda: deselect("unite"),background="#fefb00")
    deselect_dizaine=Button(zone_princ, text="✅", command=lambda: deselect("dizaine"),background="#fefb00")
    deselect_centaine=Button(zone_princ, text="✅", command=lambda: deselect("centaine"),background="#fefb00")
    add_unite=Button(zone_princ, text="+", command= lambda: cree("unite",img_unite, 1))
    add_dizaine=Button(zone_princ, text="+", command=lambda: cree("dizaine", img_dizaine, 10))
    add_centaine=Button(zone_princ, text="+", command=lambda: cree("centaine", img_centaine, 100))
    add_millier=Button(zone_princ, text="+", command=lambda: cree("millier",img_millier, 1000))
    suppr_unite=Button(zone_princ, text="-", command= lambda: suppr("unite"))
    suppr_dizaine=Button(zone_princ, text="-", command=lambda: suppr("dizaine"))
    suppr_centaine=Button(zone_princ, text="-", command=lambda: suppr("centaine"))
    suppr_millier=Button(zone_princ, text="-", command=lambda: suppr("millier"))
    
    l=30
    select_unite.place(x=(liste_unite[0]+liste_unite[2])/2,y=marge/2, anchor=W, width=l)
    select_dizaine.place(x=(liste_dizaine[0]+liste_dizaine[2])/2,y=marge/2, anchor=W, width=l)
    select_centaine.place(x=(liste_centaine[0]+liste_centaine[2])/2,y=marge/2, anchor=W, width=l)
    deselect_unite.place(x=((liste_unite[0]+liste_unite[2])/2)+l,y=marge/2, anchor=W, width=l)
    deselect_dizaine.place(x=((liste_dizaine[0]+liste_dizaine[2])/2)+l,y=marge/2, anchor=W, width=l)
    deselect_centaine.place(x=((liste_centaine[0]+liste_centaine[2])/2)+l,y=marge/2, anchor=W, width=l)
    add_unite.place(x=(liste_unite[0]+liste_unite[2])/2,y=marge/2, anchor=E, width=l)
    add_dizaine.place(x=(liste_dizaine[0]+liste_dizaine[2])/2,y=marge/2, anchor=E, width=l)
    add_centaine.place(x=(liste_centaine[0]+liste_centaine[2])/2,y=marge/2, anchor=E, width=l)
    add_millier.place(x=(liste_millier[0]+liste_millier[2])/2,y=marge/2, anchor=E, width=l)
    suppr_unite.place(x=((liste_unite[0]+liste_unite[2])/2)-l,y=marge/2, anchor=E, width=l)
    suppr_dizaine.place(x=((liste_dizaine[0]+liste_dizaine[2])/2)-l,y=marge/2, anchor=E, width=l)
    suppr_centaine.place(x=((liste_centaine[0]+liste_centaine[2])/2)-l,y=marge/2, anchor=E, width=l)
    suppr_millier.place(x=(liste_millier[0]+liste_millier[2])/2,y=marge/2, anchor=W, width=l)
    
    
    #Corbeille
    
    img_corbeille=PhotoImage(file="images/corbeille.png")
    corbeille=Label(zone_gauche, image=img_corbeille)
    corbeille.grid(row=1,column=0)
    
    #Appuis sur les touches
    
    fenetre.bind_all('<u>', lambda event: cree("unite",img_unite, 1))
    fenetre.bind_all('<d>', lambda event: cree("dizaine",img_dizaine, 10))
    fenetre.bind_all('<c>', lambda event: cree("centaine",img_centaine, 100))
    fenetre.bind_all('<m>', lambda event: cree("millier",img_millier, 1000))
    
    fenetre.bind_all('<g>', lambda event: select("millier"))
    fenetre.bind_all('<h>', lambda event: select("centaine"))
    fenetre.bind_all('<j>', lambda event: select("dizaine"))
    fenetre.bind_all('<k>', lambda event: select("unite"))
    
    
    fenetre.mainloop()
    
    
    
    
    
    

    EDIT : j'ai trouvé à peu près comment faire, il fallait ajouter un update().

    Donc j'ai deux méthodes, soit avec une boucle for + time.sleep, soit avec after.

    Dans les deux cas, le mouvement devrait se répéter toutes les 50 milisecondes, or c'est beaucoup plus rapide et fluide avec after qu'avec la boucle for. Je ne comprends pas.

    def deplacement(objet,dx,nb):
        global boucle
        if boucle<nb:
            zone_princ.move(objet, dx, 0)
            zone_princ.update()
            boucle=boucle+1
            zone_princ.after(50,deplacement(objet,dx,nb))
        #for i in range(nb):
        #    zone_princ.move(objet, dx, 0)
        #    zone_princ.update()
        #    time.sleep(0.05)





    -
    Edité par ArnaudJouski 14 janvier 2023 à 12:07:30

    • Partager sur Facebook
    • Partager sur Twitter
      14 janvier 2023 à 12:23:32

      Bonjour,

      Je déplace une balle qui rebondit dans un canvas, et je n'utilise pas update():

      def move_item():
          global stop,dx,dy,ball
      
          if(not stop):
              graph_area.move(ball,dx,dy)
              graph_area.after(100, move_item)


      Sinon, la méthode after est exactement faite pour ça, pas de boucle ni de time.sleep()

      -
      Edité par Phil_1857 14 janvier 2023 à 12:25:24

      • Partager sur Facebook
      • Partager sur Twitter
        14 janvier 2023 à 14:10:04

        ArnaudJouski a écrit:

        Comment faire ? J'ai vu des solutions avec canvas.after, mais du coup ça fait une boucle infinie, or je n'ai besoin que d'un déplacement court et borné.

        Il faut apprendre à faire avec:

        def update(count):
            ...
            if count > 0:
               widget.after(50, update, count-1)  

        ArnaudJouski a écrit:

        Donc j'ai deux méthodes, soit avec une boucle for + time.sleep, soit avec after.

        Dans les deux cas, le mouvement devrait se répéter toutes les 50 milisecondes, or c'est beaucoup plus rapide et fluide avec after qu'avec la boucle for. Je ne comprends pas.

         Ce devrait être le contraire - on a un meilleur contrôle avec update - mais quand on débute, .after est plus facile à utiliser. Mais pas sur que grand monde ait envie de passer du temps sur votre code.

        • Partager sur Facebook
        • Partager sur Twitter
          14 janvier 2023 à 14:26:06

          Ça marche, merci je m'en suis sorti avec update, finalement j'avais besoin que l'objet fasse une pause avant le départ, et après l'arrivée, donc le time.sleep.

          J'ai une autre question je ne parviens pas à résoudre.

          Je veux déplacer 10 objets que l'utilisateur a préalablement sélectionnés.

          Avec move() j'arrive à déplacer soit un seul objet en l'appelant par son ID, soit plusieurs avec un tag. Mais pas plusieurs ID contenus dans une liste.

          Donc quand sélectionne un objet, je lui ajoute un tag "pretadeplacer" avec itemconfig.

          Mais si l’utilisateur change d'avis et désélectionne un des objets, comment supprimer le tag ?

          • Partager sur Facebook
          • Partager sur Twitter
            14 janvier 2023 à 15:11:14

            ArnaudJouski a écrit:

            Mais si l’utilisateur change d'avis et désélectionne un des objets, comment supprimer le tag ?

            Dans la documentation du canvas, on trouvera la méthode dtag pour ça.

            • Partager sur Facebook
            • Partager sur Twitter
              3 février 2023 à 1:18:47

              Salut,

              ArnaudJouski a écrit:

              Avec move() j'arrive à déplacer soit un seul objet en l'appelant par son ID, soit plusieurs avec un tag. Mais pas plusieurs ID contenus dans une liste.

              Personnellement, j'utiliserais simplement une boucle FOR.

              for id in LST_DE_IDS:
                  canvas.move(id, 100, 0)

              Il y a des avantages à utiliser des tags, mais dans certains cas, ca peu devenir embêtant. Surtout, si vous avez déjà une liste, que les utilisateurs modifies, lorsqu'ils sélectionnent..

              • Partager sur Facebook
              • Partager sur Twitter

              Déplacer un objet de 100px ... et que ça se "voie"

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown