如何在Tkinter中用一个"bind"绑定多个组件?

7 投票
2 回答
8949 浏览
提问于 2025-04-17 18:48

我想知道怎么用一个“绑定”来绑定多个小部件。

比如说:

我有三个按钮,我想在鼠标悬停时改变它们的颜色。

from Tkinter import *

def SetColor(event):
    event.widget.config(bg="red")
    return

def ReturnColor(event):
    event.widget.config(bg="white")
    return

root = Tk()

B1 = Button(root,text="Button 1", bg="white")
B1.pack()

B2 = Button(root, text="Button2", bg="white")
B2.pack()

B3 = Button(root, text= "Button 3", bg="white")
B3.pack()

B1.bind("<Enter>",SetColor)
B2.bind("<Enter>",SetColor)
B3.bind("<Enter>",SetColor)

B1.bind("<Leave>",ReturnColor)
B2.bind("<Leave>",ReturnColor)
B3.bind("<Leave>",ReturnColor)

root.mainloop()

我的目标是只用两个绑定(一个是“进入”,一个是“离开”事件),而不是像上面那样需要六个。

谢谢大家的建议!

2 个回答

11

关于你问的一个绑定是否可以应用于多个小部件,答案是可以的。这样做可能会导致代码行数增加,但其实很简单。

所有的tkinter小部件都有一个叫“bindtags”的东西。bindtags是一个“标签”的列表,绑定就是附加在这些标签上的。你在使用时其实一直在用这个,只是你可能没注意到。当你给一个小部件绑定事件时,绑定并不是直接在这个小部件上,而是绑定在一个和小部件底层名称相同的标签上。默认的绑定是在一个和小部件类名相同的标签上(这里的类是指底层类,而不一定是python类)。而当你调用bind_all时,你实际上是在绑定到标签"all"

bindtags的一个好处是,你可以随意添加和删除标签。所以,你可以添加自己的标签,然后用bind_class把绑定分配给它(我也不知道为什么tkinter的作者选择这个名字……)。

需要记住的一点是,bindtags是有顺序的,事件是按照这个顺序来处理的。如果一个事件处理函数返回字符串"break",那么事件处理会在检查完剩下的bindtags之前就停止了。

这意味着,如果你想让其他绑定能够覆盖你新的绑定,就把你的bindtag放在最后。如果你希望你的绑定无法被其他绑定覆盖,就把它放在最前面。

示例

import Tkinter as tk

class Example(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)

        # add bindings to a new tag that we're going to be using
        self.bind_class("mytag", "<Enter>", self.on_enter)
        self.bind_class("mytag", "<Leave>", self.on_leave)

        # create some widgets and give them this tag
        for i in range(5):
            l = tk.Label(self, text="Button #%s" % i, background="white")
            l.pack(side="top")
            new_tags = l.bindtags() + ("mytag",)
            l.bindtags(new_tags)

    def on_enter(self, event):
        event.widget.configure(background="bisque")

    def on_leave(self, event):
        event.widget.configure(background="white")

if __name__ == "__main__":
    root = tk.Tk()
    view = Example()
    view.pack(side="top", fill="both", expand=True)
    root.mainloop()

关于bindtags的更多信息可以在这个回答中找到:https://stackoverflow.com/a/11542200/7432

此外,bindtags方法本身的文档可以在effbot的基本小部件方法页面以及其他地方找到。

7
for b in [B1, B2, B3]:
    b.bind("<Enter>", SetColor)
    b.bind("<Leave>", ReturnColor)

你可以进一步简化你的代码片段:

for s in ["button 1", "button 2", "button 3"]:
    b=Button(root, text=s, bg="white")
    b.pack()
    b.bind("<Enter>", SetColor)
    b.bind("<Leave>", ReturnColor)

现在添加额外的按钮变得很简单(只需要在输入列表中再加一个项)。而且,如果你想改变所有按钮的操作,只需修改for循环的内容就可以了。

撰写回答