Python;tkinter;画布对象与事件
我有一个类,里面包含了一些鼠标事件:
class graphic_object(object):
def mouse_click(self,event):
#do something
def mouse_move(self,event):
#do something
def mouse_unpressed(self,event):
#do something
这个类的实例并不是屏幕上的真实图形对象,但它们有自己的图形表现,形状是圆形的。正如我所说的,它们会监听鼠标事件。图形表现和事件处理都是由一个叫做 tkinter.Canvas
的对象来管理的,这个对象就像它们的视觉容器。
当我创建这个类的一个实例时:
graphic1 = graphic_object(a,b,c,d) # init method takes coordinates of the circle as arguments; a,b,c,d - numbers
一切都按预期工作,对象会以我希望的方式对鼠标事件做出反应。但是当我创建两个实例时:
graphic1 = graphic_object(a,b,c,d)
graphic2 = graphic_object(e,f,g,h)
只有最后创建的对象会对鼠标事件做出反应。
这是我用来检查鼠标是否在圆形上方的条件:
if d < self.radius:
这里 d
是鼠标位置和圆心之间的距离,而 radius
是圆的半径。
在调试器中,我发现 self.center
总是指向最后创建的对象的圆心,所以条件总是作用于第二个圆形。那么,我该如何让两个对象都能对鼠标事件做出反应呢?
事件处理:
C = Canvas()
C.bind("<Button-1>" ,self.mouse_click)
C.bind("<B1-Motion>",self.mouse_move)
C.bind("<ButtonRelease-1>",self.mouse_unpressed)
1 个回答
3
看起来你在鼠标绑定的时候,依赖了一个事先计算好的全局变量(d
)。其实这样做并不合适。你在绑定的第一步应该是获取当前鼠标的位置,然后再计算出d
。
另外一个选择是把绑定放在每个画布对象上,使用画布的tag_bind
方法。你可以参考这个问题的例子:如何在Tkinter中将事件绑定到画布上的项目?
你在这个回答的评论中提到,你有时候才能接收到鼠标点击。你的代码细节不够,无法判断你具体在做什么,但我可以肯定的是,画布通常不会出现这种问题。
我无法调试你的代码,因为你只展示了一些片段,不过这里有一个工作示例,试图说明如何使用tag_bind
。我对你的代码做了一些调整,比如我添加了一个名称参数,这样我可以打印出你点击的是哪个圆圈。当我测试这个时,每次点击似乎都能正确识别到对应的圆圈。
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(self, width=400, height=400,
background="bisque")
self.canvas.pack(fill="both", expand=True)
graphic1 = GraphicObject(10,10,100,100, name="graphic1")
graphic2 = GraphicObject(110,110,200,200, name="graphic2")
graphic1.draw(self.canvas)
graphic2.draw(self.canvas)
class GraphicObject(object):
def __init__(self, x0,y0,x1,y1, name=None):
self.coords = (x0,y0,x1,y1)
self.name = name
def draw(self, canvas, outline="black", fill="white"):
item = canvas.create_oval(self.coords, outline=outline, fill=fill)
canvas.tag_bind(item, "<1>", self.mouse_click)
def mouse_click(self, event):
print "I got a mouse click (%s)" % self.name
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()