Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind multiple widgets with one "bind" in Tkinter?

I am wondering how to bind multiple widgets with one "bind".

For expample:

I have three buttons and I want to change their color after hovering.

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()

And my goal is to have only two binds (for "Enter" and "Leave" events) instead of six as above.

Thank you for any ideas

like image 846
Milan Skála Avatar asked Mar 12 '13 13:03

Milan Skála


People also ask

How do you bind in Tkinter?

In the below example we see how to bind the mouse click events on a tkinter window to a function call. In the below example we call the events to display the left-button double click, right button click and scroll-button click to display the position in the tkinter canvas where the buttons were clicked.

Can you add 2 commands to a button in Tkinter?

The Tkinter button has only one command property so that multiple commands or functions should be wrapped to one function that is bound to this command .

How do you bind an event with a widget in Python?

Use the bind() method to bind an event to a widget.

What does bind () do in Python?

The bind() method of Python's socket class assigns an IP address and a port number to a socket instance. The bind() method is used when a socket needs to be made a server socket. As server programs listen on published ports, it is required that a port and the IP address to be assigned explicitly to a server socket.


1 Answers

To answer your specific question on whether you can have a single binding apply to multiple widgets, the answer is yes. It will probably result in more lines of code rather than less, but it's easy to do.

All tkinter widgets have something called "bindtags". Bindtags are a list of "tags" to which bindings are attached. You use this all the time without knowing it. When you bind to a widget, the binding isn't actually on the widget per se, but on a tag that has the same name as the widget's low level name. The default bindings are on a tag that is the same name as the widget class (the underlying class, not necessarily the python class). And when you call bind_all, you're binding to the tag "all".

The great thing about bindtags is that you can add and remove tags all you want. So, you can add your own tag, and then assign the binding to it with bind_class (I don't know why the Tkinter authors chose that name...).

An important thing to remember is that bindtags have an order, and events are handled in this order. If an event handler returns the string "break", event handling stops before any remaining bindtags have been checked for bindings.

The practical upshot of this is, if you want other bindings to be able to override these new bindings, add your bindtag to the end. If you want your bindings to be impossible to be overridden by other bindings, put it at the start.

Example

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()

A little bit more information about bindtags can be found in this answer: https://stackoverflow.com/a/11542200/7432

Also, the bindtags method itself is documented on the effbot Basic Widget Methods page among other places.

like image 81
Bryan Oakley Avatar answered Oct 16 '22 14:10

Bryan Oakley