Corey Robinson
Corey Robinson

Reputation: 13

Multiple Buttons to change the colours of multiple labels TKINTER, PYTHON?

So I have multiple buttons

and i need the buttons of each name: i.e. Violet button to turn the LABEL above it into violet, and purple button to turn the above LABEL purple.

AND the reset button resets them all to grey.

AND if someone could fix my code so that the spacing of the "RESET" button is between purple and Blue (but still a row down), that'd be greatly appreciated.

WHAT MY CODE DOES NOW: It turns all of the boxes all the colours. How do I make it so when I press the one button, the one label changes colour AND I wish to do this in one function if possible (i've already thought of making multiple functions and thought this would be nicer).

Import the Tkinter functions

from tkinter import *

# Create a window
the_window = Tk()


# Give the window a title
the_window.title('MULTI Button Colour')

#Variables
window_font = ('Arial', 8)
button_size = 10
label_size = 7

margin_size_width = 10
margin_size_height = 2

label_violet = Label(the_window, padx = margin_size_width, pady = margin_size_height, bg = 'grey', width = label_size)
label_violet.grid(row = 0, column = 0)
label_purple = Label(the_window, padx = margin_size_width, pady = margin_size_height, bg = 'grey', width = label_size)
label_purple.grid(row = 0, column = 1)
label_blue = Label(the_window, padx = margin_size_width, pady = margin_size_height, bg = 'grey', width = label_size)
label_blue.grid(row = 0, column = 2)
label_green = Label(the_window, padx = margin_size_width, pady = margin_size_height, bg = 'grey', width = label_size)
label_green.grid(row = 0, column = 3)

def change_colour():
if violet_button:
    label_violet['bg'] = 'violet'
if purple_button:
    label_purple['bg'] = 'purple'
if blue_button:
    label_blue['bg'] = 'blue'
if green_button:
    label_green['bg'] = 'green'
# if reset_button:
#     label_violet['bg'] = 'grey'
#     label_purple['bg'] = 'grey'
#     label_blue['bg'] = 'grey'
#     label_green['bg'] = 'grey'


violet_button = Button(the_window, text = 'Violet', width = button_size,
                        font = window_font, command = change_colour)
purple_button = Button(the_window, text = 'Purple', width = button_size,
                        font = window_font, command = change_colour)
blue_button = Button(the_window, text = 'Blue', width = button_size, 
                        font = window_font, command = change_colour)
green_button = Button(the_window, text = 'Green', width = button_size,
                        font = window_font, command = change_colour)
reset_button = Button(the_window, text = 'RESET', width = button_size,
                        font = window_font, command = change_colour)
#----------------------------------------------------------------

violet_button.grid(row = 1, column = 0, padx = margin_size_width, pady = margin_size_height)
purple_button.grid(row = 1, column = 1, padx = margin_size_width, pady = margin_size_height)
blue_button.grid(row = 1, column = 2, padx = margin_size_width, pady = margin_size_height)
green_button.grid(row = 1, column = 3, padx = margin_size_width, pady = margin_size_height)
reset_button.grid(row = 2, column = 1, pady = margin_size_height)
# Start the event loop to react to user inputs
the_window.mainloop()

Upvotes: 1

Views: 1634

Answers (2)

Novel
Novel

Reputation: 13729

You have a lot of code in there that you copy / paste. Computers are really good at repeating things with a few variables changed. You could argue that that's ALL a computer is good at. So by doing that yourself, you are doing the computer's job. Also, you are making more work for your future self if you want to change something later. It's much better to put things in a single location, so that you can make a single change later instead of changing for every label. I can see you thought about this a little already since you have so many constants. Taking that one step further is to make a "constant" widget that all your instances copy from. It's a little advanced, but here's how you would do that:

import tkinter as tk

# Constants (aka variables that don't change during the program run)
BUTTON_SIZE = 10
FONT=('Arial', 8)

class Corey(tk.Frame):
    '''a new widget that combines a Label and a Button'''
    instances = []
    def __init__(self, master=None, color='grey', **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.color = color
        self.lbl = tk.Label(self, bg=color) # set initial color
        self.lbl.grid(sticky='nsew') # sticky makes the label as big as possible
        btn = tk.Button(self, text=color.title(), width=BUTTON_SIZE, command=self.colorize, font=FONT)
        btn.grid()
        self.instances.append(self)

    def colorize(self):
        self.lbl.config(bg=self.color)

    @classmethod
    def reset(cls):
        for widget in cls.instances:
            widget.lbl.config(bg='grey')

# Create a window
the_window = tk.Tk()

# Give the window a title
the_window.title('MULTI Button Colour')

# make some Corey widgets
colors = 'violet', 'purple', 'blue', 'green'
for col, color in enumerate(colors):
    widget = Corey(the_window, color)
    widget.grid(row=0, column=col, padx=10, pady=2)

reset_button = tk.Button(the_window, text = 'RESET', width=BUTTON_SIZE, command=Corey.reset, font=FONT)
reset_button.grid(row=1, column=0, columnspan=len(colors), pady=4)

the_window.mainloop()

The immediate advantage is that in order to add or subtract colors from my version, you only have to change one line. Also, if you want to change the appearance, say add a relief or change the button to a checkbox, again you only have to change a single line. Subclasses like this are a huge part of GUI design, I recommend you jump into this as soon as you can.

Upvotes: 1

MegaIng
MegaIng

Reputation: 7886

This should do what you want:

def get_function(cmd):
    def change_colour():
        if 'violet' == cmd:
            label_violet['bg'] = 'violet'
        if 'purple' == cmd:
            label_purple['bg'] = 'purple'
        if 'blue' == cmd:
            label_blue['bg'] = 'blue'
        if 'green' == cmd:
            label_green['bg'] = 'green'
        if 'reset' == cmd:
            label_violet['bg'] = 'grey'
            label_purple['bg'] = 'grey'
            label_blue['bg'] = 'grey'
            label_green['bg'] = 'grey'
    return change_colour


violet_button = Button(the_window, text = 'Violet', width = button_size,
                        font = window_font, command = get_function('violet'))
purple_button = Button(the_window, text = 'Purple', width = button_size,
                        font = window_font, command = get_function('purple'))
blue_button = Button(the_window, text = 'Blue', width = button_size,
                        font = window_font, command = get_function('blue'))
green_button = Button(the_window, text = 'Green', width = button_size,
                        font = window_font, command = get_function('green'))
reset_button = Button(the_window, text = 'RESET', width = button_size,
                        font = window_font, command = get_function('reset'))

For the issue with the reset button, just specifie the columnspan argument of the grid function:

reset_button.grid(row = 2, column = 1, pady = margin_size_height, columnspan = 2)

Upvotes: 1

Related Questions