Yes, this works great, thanks very much. I don't want to just copy your
code though, I'm trying to understand what I'm doing wrong, so I tried
modifying my code to more or less mirror your technique. I am now
getting an unknown error message that I can't figure out, and I suspect
that I am "thinking about things" incorrectly. I've stripped things
down, even deleting the onDrag method for now, and still can't identify
what I'm doing wrong. Here's the stripped down code; now I'm only
trying to draw the box and not worrying about anything else for now:
from Tkinter import *
WINDOWWIDTH=500
WINDOWHEIGHT=500
class App: def __init__ (self,master):
self.x=10
self.y=10
self.display = Frame(master, width=WINDOWWIDTH,
height=WINDOWHEIGHT)
self.canvas=Canvas(self.display, bg='blue')
#Draw boxes, set up screen layout
self.box1=self.canvas.drawBox()
self.display.pack()
self.canvas.pack()
def drawBox(self):
newbox=self.create_rectangle(self.x, self.y, self.x+70,
self.y+70, width=5, fill='red')
self.tag_bind(newbox, '<B1-Motion>', self.onDrag)
return newbox
root= Tk()
app=App(root)
root.mainloop()
My error is "AttributeError: Canvas instance has no attribute 'drawBox'".
I've tried deleting the return statement and just calling
"self.canvas.drawBox with the same result. If I deleted the drawBox
function and just put the statements in "init", it works correctly. I
thought that by calling "self.canvas.drawBox()", I pass "self.canvas"
as self, so that in effect I am calling
"newbox=self.canvas.create_rectangle(self.x, self.y, self.x+70,
self.y+70, width=5, fill='red')". Clearly this is inaccurate because if
I write "newbox=self.create_rectangle(self.x, self.y, self.x+70,
self.y+70, width=5, fill='red')" in the init, it works correctly. Where
am I thinking about this incorrectly?
Thanks again, and sorry for all the questions - I am obviously new to
this and it has been driving me crazy.
Quoting Guilherme Polo <[EMAIL PROTECTED]>:
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