如何停止在Tkinter中触发事件?

6 投票
2 回答
4857 浏览
提问于 2025-04-17 13:23

我有一些代码,像这样:

from Tkinter import *
master = Tk()
def oval_mouse_click(event):
    print "in oval"
def canvas_mouse_click(event):
    print "in canvas"
w = Canvas(master, width = 800, height = 600)
uid = w.create_oval(390, 290, 410, 310, fill='blue')
w.tag_bind(uid, "<Button-1>", lambda x: oval_mouse_click(x))
w.bind("<Button-1>" , canvas_mouse_click)
w.pack()
mainloop()

当我点击画布(Canvas)时,控制台会显示“在画布内”的信息。
而当我点击椭圆(Oval)时,控制台会显示两条信息:“在椭圆内”和“在画布内”,但我只想看到第一条信息。有没有办法阻止事件的触发呢?

我可以用一个全局标志来解决这个问题,但我觉得对于Tkl来说,应该有更自然的方法。

2 个回答

3

我刚刚在那个类似的问题上发布了一个改进的解决方案,链接在这里:Python tkinter: 停止事件在文本小部件标签中的传播

这个解决方案的核心思路和之前的方案是一样的:通过将Canvas小部件绑定到与tag_bind相同的事件序列上来“劫持”它。我想出的改进方案现在可以模拟Tk的其他绑定+回调对中预期的return "break"行为。简单来说就是:

  1. 创建一个包装器,围绕你想要的callback,也就是一个可调用的类实例。
  2. 当这个类实例被调用时,运行callback并检查它的结果。
    • 如果结果是"break",那么暂时劫持事件传播:将Canvas小部件绑定到与tag_bind相同的事件上,并设置一个空的回调。然后,在一段空闲时间后,unbind
    • 如果结果不是"break":什么都不做,事件会自动传播到Canvas

上面的链接提供了一个完整的示例,使用的是Text小部件,但这个方法可以直接应用到Canvas小部件上。

2

这里有一个最简单的例子来解决你的问题:

import Tkinter

def oval_mouse_click(event):
    print "in oval"
    event.widget.tag_click = True

def canvas_mouse_click(event):
    if event.widget.tag_click:
        event.widget.tag_click = False
        return
    print "in canvas"

root = Tkinter.Tk()
canvas = Tkinter.Canvas(width=400, height=300)
oid = canvas.create_oval(400/2-10, 300/2-10, 400/2+10, 300/2+10, fill='blue')
canvas.tag_click = False
canvas.tag_bind(oid, "<Button-1>", oval_mouse_click)
canvas.bind("<Button-1>" , canvas_mouse_click)
canvas.pack()
root.mainloop()

Canvas中,没有比这个更简单的方法了。

撰写回答