[Tkinter-discuss] How to bind to a drawn object?

btkuhn at email.unc.edu btkuhn at email.unc.edu
Sun Nov 16 19:24:59 CET 2008


Quoting Guilherme Polo <ggpolo at gmail.com>:

> On Sun, Nov 16, 2008 at 3:47 PM,  <btkuhn at email.unc.edu> wrote:
>> Hello everyone,
>>
>> I am trying to create bindable shapes with Tkinter that are dragged when the
>> user drags with the mouse. Here is an example (some code edited out for
>> simplicity). This is all within an "App" class:
>>
>> self.canvas=Canvas(self.display, bg='blue')
>> self.canvas.bind('<B1-Motion>', self.onDrag)
>> self.x=10
>> self.y=10
>> #Draw ball, set up screen layout
>>            self.box1=self.drawBox(self.canvas)
>>       self.canvas.pack()
>>          def drawBox(self,master):
>>       newbox=master.create_rectangle(self.x, self.y, self.x+70, self.y+70,
>> width=5, fill='red')
>>              return newbox
>>      def onDrag(self,event):
>>
>>       self.canvas.move(self.box1,event.x-self.x,event.y-self.y)
>>       self.x=event.x
>>       self.y=event.y
>>
>>
>>
>>
>> This works as written, but it is not good form because it can only be used
>> with box1. <B1-Motion> is bound to the canvas rather that the box, and
>> "self.box1" is explicitly stated in the onDrag method. Therefore, if I
>> wanted to create 10 boxes (or even 2) I would have to write a new onDrag
>> method for each one. Also, if I want the box to only drag when the user
>> clicks INSIDE the box, I would have to create a new "dimensions" list for
>> each new box, and then use an if statement to see if the mouse is inside the
>> box, etc. I actually tried doing this and it makes the program run extremely
>> slow with only one box, so I don't think this is a good solution. It seems
>> logical to bind <B1-Motion> to box1 rather than the canvas, and that way the
>> box will react only if the mouse is inside the box, and I could create
>> multiple boxes, each with its own binding to <B1-Motion>. When I try to do
>> this, though, using something like this:
>>
>> newbox=master.create_rectangle(self.x, self.y, self.x+70, self.y+70,
>> width=5, fill='red')
>> newbox.bind('<B1-Motion>', self.onDrag)
>>
>> it gives me an error saying that I can't bind this method to this instance.
>
> Didn't you mean an AttributeError ? The id returned my
> create_rectangle surely doesn't have a bind method.
>
>> How can I make this work?
>
> That is why Canvas has a method called tag_bind, to bind an item in 
> the canvas:
>
> master.tag_bind(newbox, '<B1-Motion>', self.on_drag)
>
>
>>
>> Thanks!
>>
>>
>>
>>
>> _______________________________________________
>> Tkinter-discuss mailing list
>> Tkinter-discuss at python.org
>> http://mail.python.org/mailman/listinfo/tkinter-discuss
>>
>
>
>
> --
> -- Guilherme H. Polo Goncalves
>


Thanks. Yes, you're right, the message is "AttributeError: App instance 
has no attribute 'on_drag'" However, when I make this change I get no 
response at all when the program is run. My drawBox function now looks 
like this:

    def drawBox(self,master):
        newbox=master.create_rectangle(self.x, self.y, self.x+70, 
self.y+70, width=5, fill='red')
        master.tag_bind(newbox, '<B1-Motion>', self.onDrag)



and my onDrag function looks like this:

    def onDrag(self,event):

        self.canvas.move(self,event.x-self.x,event.y-self.y)
        self.x=event.x
        self.y=event.y
This looks like it should work: it passed newbox as self and the 
coordinates as event to the onDrag function, but I get no response at 
all.


More information about the Tkinter-discuss mailing list