Search code examples
pythonpython-3.xtkinter

Changing all button colors with a single function tkinter


so im trying to define a function which changes the color of all buttons avaiable in the program without having to config each one separately, something that looks like this:

def change_colors():
    #change button a, b and c colors

a = Button(text='1',command=change_color)
b = Button(text='2',command=change_color)
c = Button(text='3',command=change_color)

in this example i can just do:

def change_colors():
    a.config(bg='red')
    b.config(bg='red')
    c.config(bg='red')

but in my actual code there's alot of buttons and each button needs to do a diffrent color


Solution

  • Here's one way to handle this by leveraging lambdas (a.k.a. "anonymous functions")

    • define each tk.Button widget like you would normally
    • use config to set their command property after defining them (because you'll need to reference the buttons themselves, so they have to be created first!)
    • use a lambda to pass the button object and a color to a function that handles the color change (the lambda is used to pass dynamic arguments to the function)
    import tkinter as tk
    
    root = tk.Tk()
    
    
    def change_btn_color(btn: tk.Button, color: str) -> None:
        btn.config(bg=color)
    
    
    a = tk.Button(text='1')
    a.config(command=lambda: change_btn_color(a, 'red'))
    a.pack()
    
    b = tk.Button(text='2')
    b.config(command=lambda: change_btn_color(b, 'green'))
    b.pack()
    
    c = tk.Button(text='3')
    c.config(command=lambda: change_btn_color(c, 'blue'))
    c.pack()
    
    
    root.mainloop()
    

    If the goal instead is to change ALL of the buttons to the color assigned to a given button, the approach changes just a little.

    Here, change_btn_color gets all of the widgets in the root window, and then changes the widget's color if that widget is a tk.Button.

    Using this approach, you can set the command as you define each Button - there's no need for the separate call to config because you're not passing in the buttons themselves in this case.

    Again, we're making use of a lambda so we can pass in an argument (a color name) to the command function.

    import tkinter as tk
    
    root = tk.Tk()
    
    
    def change_btn_color(color: str) -> None:
        for widget in root.winfo_children():  # get all the widgets
            if isinstance(widget, tk.Button):  # get only the buttons
                widget.config(bg=color)
    
    
    a = tk.Button(text='1', command=lambda: change_btn_color('red'))
    a.pack()
    
    b = tk.Button(text='2', command=lambda: change_btn_color('green'))
    b.pack()
    
    c = tk.Button(text='3', command=lambda: change_btn_color('blue'))
    c.pack()
    
    
    root.mainloop()