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

GTK+ avec Python Discussion :

Dessiner la trajectoire d'une balle (PyGTK/Cairo)


Sujet :

GTK+ avec Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 65
    Par défaut Dessiner la trajectoire d'une balle (PyGTK/Cairo)
    Bonjour,

    Je poursuis dans mes demandes de noob. Je me casse la tête pour faire une application avec PyGTK et Cairo affichant une trace de la trajectoire prise par la baballe.
    Un truc simple avec Tkinter carrément invraisemblable avec Cairo.
    Pour l'instant, j'arrive afficher la balle et lui faire suivre une trajectoire droite (pour l'exemple). Pour l'animation, je crée un cercle, j'attend quelques millièmes de secondes, j'efface, je redessine mon cercle un peu plus loin et ainsi de suite.

    Ensuite, je crée un petit rectangle dont je veux me servir pour tracer la trajectoire. A un instant T, je place un petit rectangle correspondant à la position actuelle du centre de la balle, T+1 idem, T+2 ... et ainsi de suite jusqu'à T+N. La succession de tous les points formant la trajectoire suivie.

    Problème, quand j'efface mon cercle, il me vire mes points et du coup, pas de trajectoire à afficher.

    Autre remarque, lorsque je lance ma boucle, le bouton déclenchant ma fonction reste enfoncé et je ne peux plus rien faire tant que la boucle effectuant l'animation n'est pas fini. Est-ce dans ce genre de cas que je dois utiliser le module "threading" de Python?

    Si une âme charitable voulais bien m'orienter dans la bonne direction, je lui en serait très reconnaissant parce que là, je vais devenir dingo!!!
    Merci d'avance.

    Ci-dessous, un extrait de code de ce que je veux faire.

    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    #!/usr/bin/env python
    # *-*coding:Latin-1*-*
     
    # Afficher un damier et des pions de maniere aleatoire
    # Importation des modules
    import gtk
    from math import pi
    from random import randrange
    from time import sleep
     
    # Fonctions    
     
    def balle(widget, data, taille):
        "Test balle"
        x = 0
        y = 50
     
        cr = data.window.cairo_create()
     
        while x<200:
            #ligne(cr, data, x ,y)
            cr.rectangle(x, y, 1, 1)
            cr.stroke_preserve()
            cr.save()
     
            cr.set_source_rgba(0.9,0.4,0.3,0.5)
            cr.arc(x, y, taille/2, 0, 2*pi)
            cr.fill()
     
            sleep(0.005)
            cr.set_source_rgba(1.0,1.0,1.0,1)
            cr.paint()
            cr.restore()
            x += 1
     
     
    # Definition des variables
    taille = 25
     
     
    # Interface
    # Fenetre principal
    window = gtk.Window()
    window.set_resizable(False)
    window.set_border_width(12)
    window.set_position(gtk.WIN_POS_CENTER)
    window.connect("destroy", gtk.main_quit)
     
    # Definition des boites
    vbox = gtk.VBox(homogeneous = False, spacing=3)
    hbox = gtk.HBox(homogeneous = True, spacing=3)
     
    # Definition de la zone de dessin
    dessin = gtk.DrawingArea()
    dessin.set_size_request(taille*10, taille*10)
     
    # Definition des boutons
    button1 = gtk.Button(label="Tracer")
    button1.set_size_request(50, 30)
    button1.connect("clicked", balle, dessin, taille)
     
    button2 = gtk.Button(label="Quitter")
    button2.set_size_request(50, 30)
    button2.connect("clicked", gtk.main_quit)
     
    # Packing et affichge de l'interface
    hbox.pack_start(button1, expand=False, fill=True, padding=3)
    hbox.pack_start(button2, expand=False, fill=True, padding=3)
     
    vbox.pack_start(dessin, expand=False, fill=False)
    vbox.pack_start(hbox, expand=False, fill = False)
     
    window.add(vbox)
    window.show_all()
    gtk.main()
    J'en profite également pour demander autre chose sans rapport direct. Mais j'ai vu plusieurs extraits de code où l'on voit apparaître une petite étoile dans la liste des arguments d'une fonction, qu'est-ce que cela veut dire?
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    self.dim = (w, h)
            self.set_size_request(*self.dim)
    tel que représenté ci-dessus, je m'aventure à dire que l'on passe en argument w et h contenu dans self.dim
    En codage noob, j'aurai écris:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.set_size_request(w, h)
    Y a-t-il un autre intérêt, ai-je bien compris le truc ou je suis complétement à coté de la plaque?!

    Et pour finir : JOYEUX NOEL à tous !!!!

  2. #2
    Membre chevronné
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Par défaut
    Salut,

    Pour l'animation, il ne faut pas utiliser un sleep(0.05) mais plutôt gobject.timeout_add(50, balle) pour appeler la fonction balle toutes les 50 ms. Le timeout_add est l'équivalent GTK de la fonction "after" en Tkinter. Entre 2 appels, le prog va revenir automatiquement à la fonction principale gtk.main() qui se charge de mettre à jour l'affichage. Ça réglera le problème du bouton qui reste visuellement enfoncé.

    Note que la majorité des écrans a un taux de rafraichissement de 50-60 Hz, donc ça ne sert à rien de redessiner à moins de 20ms dans ce cas.

    Pour les animations avec Cairo, regarde cet exemple :
    http://cairographics.org/animationrotation/


    La notation fonction(*liste) permet de passer le contenu de la liste comme argument de la fonction, au lieu de la liste elle-même. Ça peut simplifier l'écriture dans certains cas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    coords = (10,20,200,350)
    # notation classique
    rectangle(coords[0], coords[1], coords[2], coords[3])
    # notation etoile
    rectangle(*coords)
    -

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 65
    Par défaut
    Merci monnomamoi,

    j'étais déjà tombé sur l'exemple proposé mais je ne suis pas encore assez calé pour comprendre clairement ce qui est fait.

    Pourrais-tu me présenter (ou quelqu'un d'autre) un programme de quelques lignes pour faire ce que je souhaite (un rectangle suivant une trajectoire courbe, en affichant la trajectoire suivie en temps réel (c'est vraiment cette dernière partie qui me pose problème).

    La seule alternative que je vois pour l'instant avec mon niveau, c'est de retracer tous les points à chaque itération de ma boucle en stockant les coordonnées dans une liste. Mais si l'animation dure un bout de temps, niveau performance, c'est zéro. Je pense qu'il y a une méthode plus sioux que celle-ci.

    NOTA :[mode ma life on] Je n'en ai probablement pas l'air, mais cela fait déjà de nombreuses heures que je tâtonne pour essayer d'arriver à quelques choses, sans grand succès, je l'avoue. Un bon coup de pouce sur ce problème me serait d'un grand secours.
    [mode ma life off]

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 65
    Par défaut
    Bonjour,

    juste pour dire que j'avance peu à peu dans ce que je veux faire.
    Actuellement, j'arrive à faire déplacer un cercle à l'écran en fonction de la position du pointeur souris (énorme, oui, je sais :p )
    Maintenant, je cherche à afficher les positions successives de ce même pointeur souris.
    Ne pouvant pas définir simplement si l'affichage d'un objet sera persistant ou non, j'ai donc décidé de procéder de la manière suivante:
    1 - Créer une surface Cairo (A) sur laquelle je dessinerai les positions du pointeur
    2 - Je lance mon programme et je crée un contexte 'B) où je dessine la position actuelle du pointeur
    3 - Je copie le contenu de ma surface (A) vers (B)

    Je écris un bout de code, mais celui-ci ne fonctionne pas, bien que je n'ai pas de message d'erreur particulier. Au départ, je vois bien le curseur se déplacer mais je ne vois pas les positions précédentes (la copie doit surement poser problème). Et au final, le programme se fige. Je peux juste quitter.

    Si quelqu'un peut m'expliquer où je me suis pané et me remettre sur les rails, ce serait chouettement sympa.

    Merci d'avance. Cordialement,

    Damien

    Voici le code:

    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    #! /usr/bin/env python
    # -*- coding:Latin-1 -*-
     
    # Animer un objet avec PyGTK et Cairo
    import gtk
    import gobject
    import cairo
    from math import pi
     
    # Creation d'une surface Cairo
    img = cairo.ImageSurface(cairo.FORMAT_RGB24, 24, 24)
     
    def run(widget, event):
        "Lancement de la fonction image toutes les 10ms"
        gobject.timeout_add(10, image, widget, event)
     
     
    def image(widget, event):
        "Fonction servant à mémoriser les positions successives du pointeur"
        # Je dessine dans img pour ensuite l'afficher lors de l'expose_event
        global dessin, img
     
        c = cairo.Context(img)
        c.set_line_width(4)
        xy = dessin.get_pointer()
        c.arc(xy[0], xy[1], 2, 0, 2 * pi)
        c.set_source_rgb(1, 0, 0)
        c.stroke_preserve()
     
        return img
     
     
    def expose_event(widget, event):
        "Expose"
        # Je matérialise la position du pointeur par un cercle
        # J'affiche en arrière plan la suface Cairo ou sont symbolisés
        # par des points les positions successives précédentes du pointeur
        global dessin, img
     
        ct = dessin.window.cairo_create()
        ct.set_source_surface(img, 400, 400)
        ct.paint()
     
        xy = dessin.get_pointer()
        ct.set_source_rgb(0.9, 0.1, 0.5)
     
        ct.arc(xy[0], xy[1], 10, 0, 2 * pi)
        ct.fill_preserve()
        dessin.queue_draw()
     
        #La ligne ci-dessous annule la fonction queue_draw si
        #déplacement trop rapide
        #return True (ou toute valeur differente de 0)
     
     
    window = gtk.Window()
    window.set_title("Animation PyGTK/Cairo")
    window.connect("destroy", gtk.main_quit)
     
    dessin = gtk.DrawingArea()
    dessin.set_size_request(400, 400)
    dessin.connect("motion_notify_event", run)
    dessin.connect("expose_event", expose_event)
     
    dessin.set_events(gtk.gdk.POINTER_MOTION_MASK
                      | gtk.gdk.BUTTON_PRESS_MASK)
     
    bouton1 = gtk.Button("Quitter")
    bouton1.connect("clicked", gtk.main_quit)
     
    vbox1 = gtk.VBox(False, 3)
    vbox1.pack_start(dessin)
    vbox1.pack_end(bouton1)
     
    window.add(vbox1)
    window.show_all()
     
    gtk.main()

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 65
    Par défaut
    Bonjour à tous,

    J'ai réussi à faire ce que je voulais, mais sans Cairo. Etant donné qu'à l'avenir, seul Cairo sera utilisé, je souhaiterai migrer mon code vers Cairo. Si quelqu'un pouvez m'indiquer les correspondances pour les fonction Pixmap/dessiner sur le pixmap et le faire réapparaitre à chaque "expose event" car là, je suis noyé sous la doc Cairo et j'avoue commencer à me décourager car je tatonne plus qu'autre chose.

    Merci d'avance pour votre aide.
    Damien

    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    #! /usr/bin/env python
    # -*- coding:Latin-1 -*-
     
    # Animer un objet avec PyGTK avec rémanence
    import gtk
    import gobject
     
     
    pixmap = None
     
     
    def configure_event(widget, event):
        global pixmap
        # Creation d'un nouveau pixmap d'arriere-plan de la taille voulue
        x, y, largeur, hauteur = widget.get_allocation()
        pixmap = gtk.gdk.Pixmap(widget.window, largeur, hauteur)
        pixmap.draw_rectangle(widget.get_style().white_gc,
                              True, 0, 0, largeur, hauteur)
     
        return True
     
     
    def motion_event(widget, event):
        "Detection des mouvements"
     
        xy = widget.get_pointer()
     
        gc = widget.get_style().fg_gc[gtk.STATE_NORMAL]
        pixmap.draw_point(gc, xy[0], xy[1])
     
        return True
     
     
    def expose_event(widget, event):
        "Expose"
     
        xy = widget.get_pointer()
        x, y, largeur, hauteur = event.area
        gc = widget.get_style().fg_gc[gtk.STATE_NORMAL]
        widget.window.draw_drawable(gc, pixmap, x, y, x, y, largeur, hauteur)
     
        # On colorie la balle en rouge en passant le contexte en rouge
        gc.set_rgb_fg_color(gtk.gdk.color_parse("red"))
        dessin.window.draw_arc(gc, True, xy[0] - 25, xy[1] - 25,
                               50, 50, 0, 360 * 64)
        # On redessine en noir (autre methode en donnant les valeurs RGB)
        gc.set_rgb_fg_color(gtk.gdk.Color(0, 0, 0))
        widget.queue_draw_area(xy[0] - 25, xy[1] - 25, 50, 50)
     
        return False
     
     
    window = gtk.Window()
    window.set_title("Animation PyGTK")
    window.connect("destroy", gtk.main_quit)
     
    dessin = gtk.DrawingArea()
    dessin.set_size_request(400, 400)
    dessin.connect("motion_notify_event", motion_event)
    dessin.connect("configure_event", configure_event)
    dessin.connect("expose_event", expose_event)
     
    dessin.set_events(gtk.gdk.EXPOSURE_MASK
                        | gtk.gdk.LEAVE_NOTIFY_MASK
                        | gtk.gdk.BUTTON_PRESS_MASK
                        | gtk.gdk.POINTER_MOTION_MASK
                        | gtk.gdk.POINTER_MOTION_HINT_MASK)
     
    bouton1 = gtk.Button("Quitter")
    bouton1.connect("clicked", gtk.main_quit)
     
    vbox1 = gtk.VBox(False, 3)
    vbox1.pack_start(dessin)
    vbox1.pack_end(bouton1)
     
    window.add(vbox1)
    window.show_all()
     
    gtk.main()

Discussions similaires

  1. casse-briques : trajectoire d'une balle
    Par josmiley dans le forum Programmation multimédia/Jeux
    Réponses: 5
    Dernier message: 16/02/2011, 19h21
  2. Dessiner une droite avec Cairo
    Par Gamall dans le forum GTK+ avec C & C++
    Réponses: 2
    Dernier message: 31/10/2009, 09h23
  3. [Qt] dessiner une balle et la déplacer
    Par lionrouge dans le forum Qt
    Réponses: 10
    Dernier message: 22/10/2006, 12h16
  4. Réponses: 2
    Dernier message: 02/07/2005, 19h14

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