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 :

Comment faire bouger des instances d'une classe "voiture" sur un canvas ?


Sujet :

Tkinter Python

  1. #1
    Membre régulier
    Homme Profil pro
    Amateur débutant
    Inscrit en
    Décembre 2019
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Amateur débutant

    Informations forums :
    Inscription : Décembre 2019
    Messages : 88
    Points : 104
    Points
    104
    Par défaut Comment faire bouger des instances d'une classe "voiture" sur un canvas ?
    Bonjour,

    Pourriez vous m'aider à comprendre comment "conceptualiser au mieux" l'outil classes?

    Par exemple si on se fixe de faire une classe Voiture:
    et de faire bouger ensuite (i.e. avec move(), after() ), de façons différentes, des instances de cette classe sur un canvas.
    Comment structurer classe, méthode, fenetre Tk, canvas? Ou et comment placer after() pour que voit1 bouge?

    Autrement dit, comment feriez vous proprement (et en m'expliquant un peu hein ) ce cas de figure?
    En tous cas merci d'avance pour toute forme d'enseignement.

    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
     
    from tkinter import *
     
    class voiture:
        """ classe fabriquant des objets voiture """
        def __init__(self, couleur, canvas, x1, y1, taille):
            self.couleur = couleur
            self.can = canvas
            self.x1 = x1
            self.y1 = y1
            self.taille = taille
            self.w = self.can.create_rectangle(self.x1, self.y1, self.x1+self.taille, self.y1+self.taille, fill=self.couleur)
     
        def bouge(self, dx, dy, vitesse ):
            self.dx = dx
            self.dy = dy
            self.vitesse = vitesse
            self.can.move(self.w, self.dx, self.dy)
     
     
    # creation fenetre
    fen = Tk()
    # creation canvas
    canW = 500
    canH = 500
    canBg = "ivory"
    can = Canvas(fen, height=canH, width=canW, bg=canBg)
    can.pack()
     
    # instanciation de deux objets voiture
    voit1 = voiture("red", can, 10, 20, 50)
    voit2 = voiture("blue", can, 50, 60, 25)
     
    # application de la methode bouge() aux "voitures"
    voit1.bouge(200, 200, 500)
    voit2.bouge(100, 100, 1000)
    # gestionaire d'evenement bouclé
    fen.mainloop()

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

    Citation Envoyé par Jma06 Voir le message
    Comment structurer classe, méthode, fenetre Tk, canvas? Ou et comment placer after() pour que voit1 bouge?
    Il serait plus simple que vous essayiez de coder quelque chose pour illustrer les questions que vous vous posez.

    "structurer" i.e. c'est juste définir la hiérarchie de boîtes dans laquelle ranger le code.

    Partez de la structure minimale que vous offre tkinter: pas besoin de classes, une fonction pour créez les rectangles que vous appelez "voitures", un tag "voiture" pour avoir la liste de toutes les voiture, un tag "moving" pour savoir celles qui se déplacent (vous pouvez remplacer tags par listes Python). Et un seul .after qui va faire bouger les "moving" toutes les ... ms.

    Après si vous voulez fabriquer une classe Voiture, déjà il faut expliquer ce que çà va apporter par rapport à la baseline précédente.
    Et çà il n'y a que vous pour le dire.

    - W

  3. #3
    Membre régulier
    Homme Profil pro
    Amateur débutant
    Inscrit en
    Décembre 2019
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Amateur débutant

    Informations forums :
    Inscription : Décembre 2019
    Messages : 88
    Points : 104
    Points
    104
    Par défaut
    Bonjour Wiztricks,

    Citation Envoyé par wiztricks Voir le message
    Après si vous voulez fabriquer une classe Voiture, déjà il faut expliquer ce que çà va apporter par rapport à la baseline précédente.
    Et çà il n'y a que vous pour le dire.
    A vrai dire, je voudrai traiter d'une classe pour apprendre comment ça peut (doit?) fonctionner en pratique.
    Le faire avec des conseils de pro m'apporterai (je pense, j'espère) de ne pas trop "apprendre de travers".
    Je suis parti sur l'exemple voiture car cela me semblait adapté de faire des objets avec des caractéristiques (couleur, taille) et une méthode pour les bouger..

    Pour cause, je vois parfois des fenêtres Tk directement initialisées dans la classe, ou parfois que le canvas... j'ai du mal a me faire une religion.
    voila pourquoi j'ai préféré venir "travailler cette question" ici avec votre aide et cet exemple.


    Cela dit, votre proposition d'une structure basale, sans classe, est si chouette que je vais essayer de m'y avancer.
    Merci

  4. #4
    Membre régulier
    Homme Profil pro
    Amateur débutant
    Inscrit en
    Décembre 2019
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Amateur débutant

    Informations forums :
    Inscription : Décembre 2019
    Messages : 88
    Points : 104
    Points
    104
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Il serait plus simple que vous essayiez de coder quelque chose pour illustrer les questions que vous vous posez.
    j'ai bien essayé de faire le petit bout de code fourni dans mon premier message, mais je sais pas si je me suis pas déjà complètement fourvoyé, si j'ai pas mis des self. qui servent à rien etc..
    c'est d’ailleurs en écrivant ce lignes que je suis dit qu'il faudrait me faire aider avant de partir dans des "mauvaise habitudes".

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

    Citation Envoyé par Jma06 Voir le message
    j'ai bien essayé de faire le petit bout de code fourni dans mon premier message, mais je sais pas si je me suis pas déjà complètement fourvoyé, si j'ai pas mis des self. qui servent à rien etc..
    Pour chaque instruction/ligne que vous avez écrite, essayez par vous même de répondre aux questions: est-elle nécessaire? à quoi sert-elle?
    Si vous êtes "confortable" avec le code que vous avez écrit...çà va bien. Sinon racontez ce qui nous chagrine.

    note: dans 6 mois, si vous continuez à apprendre à programmer, vous y trouverez des défauts par vous même. Le code ne marchera pas mieux, votre regard aura changé.

    - W

  6. #6
    Membre régulier
    Homme Profil pro
    Amateur débutant
    Inscrit en
    Décembre 2019
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Amateur débutant

    Informations forums :
    Inscription : Décembre 2019
    Messages : 88
    Points : 104
    Points
    104
    Par défaut
    Oui je vous rejoins à 100%

    Tenez, j'ai essayé ce petit quelque chose, sans classe, en essayant l'approche "basale" que vous aviez évoquée.
    j'ai pris un dico (car ça m'a fait un training, j'avais encore jamais eu l'occasion d'en utiliser un )

    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
     
    from tkinter import *
     
    def voiture(couleur, taille, x1, y1, voitNom):
        global voitures
     
        # eviter d'avoir deux clefs identiques dans le dict
        if voitNom not in voitures.keys():
            voitures[voitNom] = can.create_rectangle(x1, y1, x1+taille, y1+taille, fill=couleur, tag=voiture )
        # sinon on crée un nom generique incrémenté d'après le nombre d'eléments du dict
        else:
            nomGen = "Car#"+str(len(voitures)+1)
            voitures[nomGen] = can.create_rectangle(x1, y1, x1+taille, y1+taille, fill=couleur, tag=voiture )
     
     
    def bouge(vitesse, nomVoit ):
        dx=5
        dy=5
        voitId = voitures[nomVoit]
        c = can.coords(voitId)
        can.move(voitId, dx, dy)
        can.after(vitesse, lambda: bouge(vitesse, nomVoit))
     
     
    # creation fenetre
    fen = Tk()
     
    # creation canvas
    canW = 500
    canH = 500
    canBg = "ivory"
    can = Canvas(fen, height=canH, width=canW, bg=canBg)
    can.pack()
     
    # dico avec clef nom de voiture et valeur son id canvas
    voitures = {}
     
    # creation de deux voitures différentes
    voiture("red", 100, 10, 10, "titine")
    voiture("blue", 100, 100, 100, "tuture")
     
    # faire bouger une des voitures
    bouge(500, "titine")
     
    # gestionaire d'evenement bouclé
    fen.mainloop()
    Ça fait le petit job que je lui demande.
    Du coup avec une "classe" ça pourrait donner un truc comme ça:
    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
     
    from tkinter import *
     
    class voiture:
        """ classe fabriquant des objets voiture """
        def __init__(self, couleur, canvas, x1, y1, taille):
            self.couleur = couleur
            self.can = canvas
            self.x1 = x1
            self.y1 = y1
            self.taille = taille
            self.w = self.can.create_rectangle(self.x1, self.y1, self.x1+self.taille, self.y1+self.taille, fill=self.couleur)
     
        def bouge(self, dx, dy, vitesse ):
            self.dx = dx
            self.dy = dy
            self.vitesse = vitesse
            self.can.move(self.w, self.dx, self.dy)
            self.can.after(self.vitesse, lambda: self.bouge(dx, dy, vitesse) )
     
     
    # creation fenetre
    fen = Tk()
    # creation canvas
    canW = 500
    canH = 500
    canBg = "ivory"
    can = Canvas(fen, height=canH, width=canW, bg=canBg)
    can.pack()
     
    # instanciation de deux objets voiture
    voit1 = voiture("red", can, 10, 20, 50)
    voit2 = voiture("blue", can, 50, 60, 25)
     
    # application de la methode bouge() aux "voitures"
    voit1.bouge(10, 10, 500)
    voit2.bouge(25, 25, 1000)
    # gestionaire d'evenement bouclé
    fen.mainloop()
    Pour circonstancier une question claire:
    Comment l'auriez vous écrite pour que ce soit propre?
    car je sais pas si c'est utile, pour ne citer que ce doute, d'initier le canvas dans la classe..

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

    Je vous ai déjà suggéré de vous relire et de réfléchir aux instructions que vous avez écrit.

    Déjà dans ces quelques lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def voiture(couleur, taille, x1, y1, voitNom):
        global voitures
     
        # eviter d'avoir deux clefs identiques dans le dict
        if voitNom not in voitures.keys():
            voitures[voitNom] = can.create_rectangle(x1, y1, x1+taille, y1+taille, fill=couleur, tag=voiture )
    A quoi sert le global voitures?
    Si vous avez ouvert la documentation du Canvas, vous sauriez que canvas.create_... retourne un identifiant unique (pour la durée de vie du Canvas). Donc le if voitNom not in voitures.keys() ne sert à rien.
    Enfin si vous stockez vos identifiants dans une collection liste/dictionnaire côté Python, inutile d'avoir par dessus un tag.

    Si déjà en écrivant ces quelques lignes vous n'arrivez pas à vous relire de façon "critique" (est ce que j'ai écrit sert à quelque chose? pourquoi?), ajouter des difficultés comme les classes est un peu prématuré.

    - W

  8. #8
    Membre régulier
    Homme Profil pro
    Amateur débutant
    Inscrit en
    Décembre 2019
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Amateur débutant

    Informations forums :
    Inscription : Décembre 2019
    Messages : 88
    Points : 104
    Points
    104
    Par défaut
    Merci pour ce retour wiztricks, qui, même s'il ne semble plus cacher un certain agacement (et pourrait même être décourageant pour de plus jeunes amateurs que moi), est très profitable.

    C'est super bien je trouve (sur le fond) d'apprendre en ayant vos explications - de où et pourquoi on se trompe, ce qui ne sert a rien, ce qu'on fait mal.
    Peut en importe la forme c'est ça que je viens chercher... et je suis servi

    A propos de relecture critique, voici pourquoi j'ai fait ce qui semble être ici inutile.
    Donc le if voitNom not in voitures.keys() ne sert à rien.
    Je croyais que si, dans un dico, on entrait deux fois le même nom de clef, le dernier entré écrasait l'ancien.
    c’était juste pour éviter cet écrasement (au cas ou un nom de voiture identique aurait été envoyé a voiture().. )

    Pourquoi avoir placé global voitures?
    Je croyait qu'il fallait le faire. Car voitures est modifié par la fonction voiture() et est réutilisée dans bouge()

    Si vous wiztricks, et/ou un/une autre membre de cette board, avez un peu de temps à me consacrer, ce sera avec plaisir de vous lire (quelque en soit la forme ).

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 302
    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 302
    Points : 36 801
    Points
    36 801
    Par défaut
    Citation Envoyé par Jma06 Voir le message
    Merci pour ce retour wiztricks, qui, même s'il ne semble plus cacher un certain agacement (et pourrait même être décourageant pour de plus jeunes amateurs que moi), est très profitable.
    Il ne faut pas se décourager: relire sa prose/son code avec un regard critique est un exercice que vous devez apprendre à faire. Sûr que c'est pas facile d'avoir passé du temps à écrire çà et de prendre une question par ligne.
    J'essaie juste d'illustrer "poser vous des questions".

    Je croyais que si, dans un dico, on entrait deux fois le même nom de clef, le dernier entré écrasait l'ancien.
    Je réalise que je n'ai pas compris ce que vous cherchiez à faire car vous avez bizarrement mélangé tags et dictionnaire. Supprimez l'un ou l'autre et décrivez l'intérêt de la collection d'objets que vous voulez réaliser avant.
    note: Quand on lit du code, on essaie de comprendre l'intention du programmeur. Si c'est un peu brouillon ou qu'on lit trop vite, on se fait avoir. Désolé mais je ne comprends toujours pas à quoi çà sert.

    Citation Envoyé par Pourquoi avoir placé global voitures?
    Je croyait qu'il fallait le faire. Car voitures est modifié par la fonction voiture() et est réutilisée dans bouge()
    Le mot clef global sert a autoriser une fonction a assigner un autre objet à voitures.
    Si voitures est une collection et que vous lui ajoutez/supprimez des... vous n'assignez rien à voitures. vous modifiez l'objet (qui sera dit mutable).

    - W

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

    Un exemple de code "minimal" qui utilise des tags.

    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
    import tkinter as tk
     
    def do_move(delay):
        canvas.move('m', 5, 5)
        canvas.after(delay, do_move, delay)
     
    canvas = tk.Canvas()
    canvas.pack()
     
    for i, color in enumerate(('red', 'blue', 'green', 'grey')):
        x = y = i * 50
        tag = ['v', ('v', 'm')][i % 2]
        canvas.create_oval(x, y, x+20, y+20, fill=color, tag=tag)
     
    do_move(200)
    tk.mainloop()
    Dans les trucs qui ne servent à rien:
    • ligne 5: canvas.after(delay, do_move, delay) est juste là pour vous montrer qu'on peut passer des paramètre positionnel (le côté Tk de la chose). On pourrait aussi déclarer delay=200 comme paramètre par défaut (le côté Python).
    • ligne 11: x = y = i * 50. J'aurais pu réutiliser "x" plutôt que créer un "y". Mais comme je m'embrouillais avec les paramètres à passer à .create_oval, j'ai préféré le faire comme çà.
    • ligne 12: on ne va se servir que du tag 'm', 'v' est juste là pour vous montrer comment avoir plusieurs tags sur un même item.


    Ça c'était un code minimaliste.

    Si j'étais parti à écrire une petite application tkinter, j'aurais plutôt écrit:
    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
    import tkinter as tk
     
    def do_move(delay):
        canvas.move('m', 5, 5)
        canvas.after(delay, do_move, delay)
     
    def canvas_create(window):
     
        canvas = tk.Canvas()
        for i, color in enumerate(('red', 'blue', 'green', 'grey')):
            x = y = i * 50
            tag = ['v', ('v', 'm')][i % 2]
            canvas.create_oval(x, y, x+20, y+20, fill=color, tag=tag)
     
        return canvas
     
    if __name__ == '__main__':
        root = tk.Tk()
     
        canvas = canvas_create(root)
        canvas.pack()
        do_move(200)
     
        tk.mainloop()

    Le "if __name__ == '__main__':" est une séparation visuelle (fonctionnellement, çà ne sert pas): il y a un "au-dessus" et un "au dessous".
    Le "root = tk.Tk()" n'est là parce que j'en aurais certainement besoin plus tard.

    Vous voyez aussi que les 2 fonctions accèdent au canvas. Si on est un fondu de la POO on pourrait les regrouper dans une classe. Pour moi, c'est un peu prématuré et "canvas_create" est un entre 2 (j'utilise une notation qui va bien lorsqu'on n'a pas de "class").

    Tout çà pour dire que tant que le code fonctionne on peut se retrouver avec des codes assez différents. C'est une question d'arbitrage "raisonnable". Si on sait dire pourquoi, c'est à priori OK.

    - W

  11. #11
    Membre régulier
    Homme Profil pro
    Amateur débutant
    Inscrit en
    Décembre 2019
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Amateur débutant

    Informations forums :
    Inscription : Décembre 2019
    Messages : 88
    Points : 104
    Points
    104
    Par défaut merci ! !
    Bonjour Wiztricks,
    Je vous suis reconnaissant du temps que vous avez du passer pour moi.
    Vos explications en appuis de votre code sont claires, ça aide tant. Très chouette, vraiment.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tag = ['v', ('v', 'm')][i % 2]
    Je trouve ça beau. En une courte ligne, une astuce pour intervertir les tags tout en montrant qu'on peut utiliser plusieurs tag pour un item.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    canvas.after(delay, do_move, delay)
    et si me m'amuse à faire canvas.after(delay, do_move, delay-5).... oh oui! ça marche, ça accélère
    Me suis régalé à vous lire et tester vos lignes.

Discussions similaires

  1. Liste des instances d'une classe
    Par alexdevl dans le forum Général Python
    Réponses: 32
    Dernier message: 14/09/2011, 22h52
  2. Réponses: 0
    Dernier message: 26/06/2009, 09h23
  3. Nommer des instances d'une classe dynamiquement ?
    Par Demosis dans le forum Langage
    Réponses: 4
    Dernier message: 04/11/2007, 14h22
  4. Réponses: 9
    Dernier message: 18/10/2007, 20h06
  5. Comment faire apparaitre des données dans une listbox
    Par nuans dans le forum Interfaces Graphiques
    Réponses: 3
    Dernier message: 14/05/2007, 15h04

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