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

EDI/RAD Python Discussion :

Evenement Motion sur 2 objets


Sujet :

EDI/RAD Python

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 121
    Points : 80
    Points
    80
    Par défaut Evenement Motion sur 2 objets
    Bonjour,

    Pour tester, j'ai fait ç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
     
    from Tkinter import *
     
    fen=Tk()
    fen.geometry("400x400")
     
    C=Canvas(fen,width=200,height=200,bg="white")
    C.place(x=100,y=100)
     
    def info(e):
        print ": x=",e.x,"y=",e.y
     
    def deplaceF(evt) :
        print "Deplacement sur la fenetre",
        info(evt)
     
    def deplaceC(evt) :
        print "Deplacement sur le canevas",
        info(evt)
     
    C.bind( '<Motion>', deplaceC )
    fen.bind( '<Motion>', deplaceF )
     
    fen.mainloop()
    Quand je déplace la souris sur mon canevas, je vois bien que les 2 évènements se produisent, par contre, je m'attendais à ce que les coordonnées soient différente puisque pour moi relative à chacun des objets. Comment expliquer cela ?

    Merci,

    Vincent

  2. #2
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonjour,

    bind s'applique aux enfants donc si vous écrivez
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fen.bind( '<Motion>', deplaceF )
    Cela s'applique aussi pour C.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from Tkinter import *
     
    fen = Tk()
    fen.geometry("400x400")
     
    C = Canvas(fen, width=200, height=200, bg="white")
    C.place(x=100, y=100)
     
    def deplace(evt) :
        print "Deplacement sur le widget %s: : x=%d, y=%d" % (evt.widget, evt.x, evt.y)
     
    fen.bind('<Motion>', deplace)
     
    fen.mainloop()
    Comme vous écrivez
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    C.bind( '<Motion>', deplaceC )
    Vous créez aussi un event juste pour C.
    Lorsque '<Motion>' se produit seul le Widget qui a le focus (event.widget) est concerné mais les deux fonctions callback sont appelées.
    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
    from Tkinter import *
     
    fen = Tk()
    fen.geometry("400x400")
     
    C = Canvas(fen, width=200, height=200, bg="white")
    C.place(x=100, y=100)
     
    def Clic(evt) :
        print "Clic sur %s" % evt.widget
     
    fen.bind('<1>', Clic)
    C.bind('<1>', Clic)
     
    fen.mainloop()
    @+
    Merci d'utiliser le forum pour les questions techniques.

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

    La réponse de Pausekawa est "juste" mais je ne la trouve pas assez précise.

    Quand je déplace la souris sur mon canevas, je vois bien que les 2 évènements se produisent, par contre, je m'attendais à ce que les coordonnées soient différente puisque pour moi relative à chacun des objets. Comment expliquer cela ?
    La réponse courte pourrait être: il s'agit d'un même évènement "dans la window qui a le focus" propagé via la mécanique des bindtags et non de la génération d’événements spécifique à chacune des "windows".

    Une réponse plus longue demande de regarder un peu à quoi correspond tout çà.

    Lorsqu'on crée un binding (avec la commande bind) on l'associe à un "tag".

    Un tag est une chaine de caractères qui peut correspondre au nom Tk de la window associée à l'instance de l'objet tkinter ou à un widget genre 'Canvas' ou 'Button' (qui sera une classe côté tkinter).
    note: Tk est la bibliothèque graphique, tkinter la bibliothèque Python qui sert d'interface à Tk
    Par défaut, le nom Tk donné par Tkinter est construit à partir de l'id de l'instance.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> r = tk.Tk()
    >>> r._w
    '.'                    # la root
    >>> f = tk.Frame(r)
    >>> id(f)
    39943120         # l'adresse mémoire de l'instance est "unique"...
    >>> f._w
    '.39943120'       # nom construit à partir de id(f)
    Mais on peut donner ses propres "noms" via l'attribut name=...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> c = tk.Canvas(r, name='mycanvas')
    >>> f = tk.Frame(c, name='frame')
    >>> f._w
    '.mycanvas.frame'

    Par défaut, chaque window Tk (ou instance de... Tkinter) a 4 binding tags associés:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> c = tk.Canvas(r, name='mycanvas')
    >>> c.bindtags()
    ('.mycanvas', 'Canvas', '.', 'all')
    l'instance, la classe, la toplevel et "all".
    Ces "bindtags" définissent l'ordre dans lequel sera propagé un event dans le cas ou bind aura été défini sur ces "tags" // instance // Classes.
    Ceci dit un event est souvent généré par la window qui a le 'focus'.
    Dans le cas d'un "mouse" event, c'est la fenetre qui est juste "sous" la souris mais pour un keyboard event c'est "autre chose".

    Reprenons l'exemple:
    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
    import tkinter as tk
    from tkinter.constants import *
     
    r = tk.Tk()
    r.geometry("400x400")
    menu = tk.Menu(r)
    r['menu'] = menu
    menu.add_command(label='next', command=r.quit)
     
    c = tk.Canvas(r,width=200,height=200,bg="white", name='canvas')
    c.place(x=100, y=100)
     
    def show_event(event, bound_to=None):
        print ('bound_to=%s' % bound_to)
        print ('widget:%s, tk tag: %s, x: %d, y:%d, x_root: %d, y_root:%d,' % (
                 event.widget, event.widget._w,
                 event.x, event.y, event.x_root, event.y_root) )
     
    print ('default behaviour') 
    c.bind( '<1>', lambda e: show_event(e, bound_to='canvas' ))
    r.bind( '<1>', lambda e: show_event(e, bound_to='root' ))
    r.mainloop()
    Ca affiche:
    • Click dans le canvas => le même event est propagé à c, puis r
      bound_to=canvas
      widget:.canvas, tk tag: .canvas, x: 114, y:111, x_root: 397, y_root:436,
      bound_to=root
      widget:.canvas, tk tag: .canvas, x: 114, y:111, x_root: 397, y_root:436,
    • Click dans la root => l'event n'est propagé qu'à r
      bound_to=root
      widget:., tk tag: ., x: 196, y:40, x_root: 233, y_root:195,

    On peut changer le comportement de plusieurs façons:
    1. l'instance du canvas bloque la propagation à l'élement suivant de la liste.
    2. En modifiant la liste des bindtags.
    blocage de la propagation, le handler de l'event retourne "break":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    print ('using break')
    def do_break(event):
        print ('widget:%s, tk tag: %s, x: %d, y:%d, x_root: %d, y_root:%d,' % (
                 event.widget, event.widget._w,
                 event.x, event.y, event.x_root, event.y_root) )
        return 'break'
    c.bind( '<1>', do_break)
    r.bind( '<1>', do_break)
    r.mainloop()
    Dans ce cas, r (la toplevel) ne reçoit plus les "clics" générés dans la window c.
    modification de la liste des bindtags.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    print ('change bindtags')
    print ('c.bindtags() => %s' % ', '.join(c.bindtags()))
    print ('c.bindtags() => %s' % ', '.join(c.bindtags()))
    saved_tags = c.bindtags()
    c.bind( '<1>', lambda e: show_event(e, bound_to='canvas' ))
    r.bind( '<1>', lambda e: show_event(e, bound_to='root' ))
    c.bindtags(('.canvas', 'all'))
    r.mainloop()
    Dans ce cas, nous avons exclu la toplevel des bindtags, elle ne reçoit pas non plus les events.

    Maintenant, pour récupérer la position relative de l'event dans le repère relatif de la toplevel, utilisez les coordonnées reçues dans event.x_root, event.y_root (plutôt que event.x, event.y)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    print ('restore bindtags')
    c.bindtags(saved_tags)
    def show_window(event):
        w = event.widget
        show_event(event)
        toplevel = w.winfo_toplevel()
        x = event.x_root - toplevel.winfo_rootx();
        y = event.y_root - toplevel.winfo_rooty()
        print ('x = %d, y = %d' % (x, y))
    r.bind( '<1>', show_window)
    r.mainloop()

    Bon courage,
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 121
    Points : 80
    Points
    80
    Par défaut
    Super ! Merci à vous deux pour ces réponses très détaillées.

    Vincent

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

    Juste un cut&paste de la documentation tk de bind qui mentionne une exception à la règle:

    ButtonPress, ButtonRelease, Motion
    The ButtonPress and ButtonRelease events are generated when the user presses or releases a mouse button. Motion events are generated whenever the pointer is moved. ButtonPress, ButtonRelease, and Motion events are normally sent to the window containing the pointer.

    When a mouse button is pressed, the window containing the pointer automatically obtains a temporary pointer grab. Subsequent ButtonPress, ButtonRelease, and Motion events will be sent to that window, regardless of which window contains the pointer, until all buttons have been released.
    Dans la pratique cela signifie que lorsqu'on attrape la suite ButtonPress=>Motion=>ButtonRelease, le widget de l'event sera toujours le widget de départ (celui du ButtonPress) et non celui ou sera placé la souris.
    Mais on peut récupérer celui ci via .winfo_containing(event.x_root, event.y_root)

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [Flex4] Evenement d'écoute sur l'objet data d'un renderer
    Par Taliel dans le forum Flex
    Réponses: 2
    Dernier message: 11/02/2014, 08h28
  2. evenement click sur un objet
    Par ibrsoft dans le forum Général Python
    Réponses: 6
    Dernier message: 27/07/2013, 16h53
  3. Evenement move sur des objets dynamique
    Par thierry007 dans le forum VB.NET
    Réponses: 8
    Dernier message: 10/04/2012, 14h06
  4. Evenement Click sur un tableau d'objets
    Par the-morpher dans le forum Windows Forms
    Réponses: 3
    Dernier message: 18/03/2009, 13h47
  5. [SWING] Evenement (souris) sur un objet Chartpanel
    Par rprom1 dans le forum AWT/Swing
    Réponses: 1
    Dernier message: 20/04/2006, 10h10

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