On Sun, Nov 16, 2008 at 4:24 PM, <[EMAIL PROTECTED]> wrote: > Quoting Guilherme Polo <[EMAIL PROTECTED]>: > >> On Sun, Nov 16, 2008 at 3:47 PM, <[EMAIL PROTECTED]> 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! >>> >> >> -- >> -- 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.
I suspect there are other things wrong in your app then. > 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) > Don't you want a ButtonPress-1 there too ? > > > 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. > Uhm, no, self is the class instance so it is surely not the newbox item. Well, I've done a sample here based on what you are after, check if this works for you: import Tkinter class Boxes(Tkinter.Canvas): def __init__(self, master=None, **kw): Tkinter.Canvas.__init__(self, master, **kw) def create_box(self, x, y, size, **kw): box = self.create_rectangle(x, y, x + size, y + size, **kw) self.tag_bind(box, '<ButtonPress-1>', self.on_click) self.tag_bind(box, '<B1-Motion>', self.on_drag) def on_click(self, event): self.curr_x = event.x self.curr_y = event.y def on_drag(self, event): x, y, _, _ = self.coords('current') self.move('current', (event.x - self.curr_x), (event.y - self.curr_y)) self.curr_x = event.x self.curr_y = event.y app = Boxes(bg='blue') app.create_box(10, 10, 70, width=5, fill='red') app.create_box(20, 20, 70, width=5, fill='yellow') app.pack() app.mainloop() -- -- Guilherme H. Polo Goncalves _______________________________________________ Tkinter-discuss mailing list Tkinter-discuss@python.org http://mail.python.org/mailman/listinfo/tkinter-discuss