0

I have never created a GUI before and I decided to try to create one in Python3, using tkinter.

I would like to create a 5x5 "matrix" of buttons that change color and text when pressed. After some googling, I figure out how to do it for a single button and in principle I could just copy-paste and create the 25 buttons I need. However I'd like to find a more elegant way to do it inside a loop. My problem is that I need to give different names to each button, but I don't know how to do that.

I hope the question is clear enough. Thank you in advance for any help!!

Onil90
  • 171
  • 1
  • 8

1 Answers1

1

Here is a very simple example on how to do so, by making a list of all the 25 color and then using the conventional matrix looping and assigning items to the buttons, like:

from tkinter import *

root = Tk()

colors = ['Red','Orange','Yellow','Green','Blue','Purple','Brown','Magenta',
        'Tan','Cyan','Olive','Maroon','Navy','Aquamarine','Turquoise','Silver',
        'Lime','Teal','Indigo','Violet','Pink','Black','White','Gray','crimson']
colors = list(reversed(colors)) # Reversing list bc pop returns last item

def color_changer(btn,color):
    btn.config(fg=color) # Change the color of the corresponding button

for i in range(5): # Number of rows
    for j in range(5): # Number of column
        color = colors.pop()  # First color
        btn = Button(root,text=color,fg='black',width=25)
        btn.grid(row=i,column=j) # Place the widget
        btn['command'] = lambda btn=btn,color=color: color_changer(btn,color) # Assign a command

root.mainloop()

There is a caveat here, you should define exactly 25 colors, else, you should use try to catch the IndexError that comes up and ignore it.

How does the function work?: You are using lambda to create a new nameless function that takes in btn and color and passes that btn and color to the color_changer(). This way we can store corresponding btn and color, unlike if you would normally assign it like lambda: color_changer(btn,color), it is just going to pass the last popped item. This is usually how we assign commands for buttons inside a loop.

Alternative(to lambda): You can also use a nested function(avoiding lambdas). So the function would be like:

def nester(btn,color):
    def color_changer():
        btn.config(fg=color)
    return color_changer

and the command would be like:

btn['command'] = nester(btn,color)

This is similar to what functools.partial does.

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
  • A last question: is there a way to make the color change immediately? I noticed that it changed only after the pointer moves away from the pressed button. – Onil90 Jan 31 '21 at 17:09
  • @Onil90 The color changes only if you press the button, as your question states, "_I would like to create a 5x5 "matrix" of buttons that change color and text when pressed._". – Delrius Euphoria Jan 31 '21 at 17:11
  • Yes, that's right! And it does work fine. However I wonder why I can see the color only after the pointer leaves the button. – Onil90 Jan 31 '21 at 19:30
  • @Onil90 That's weird, by no means shall the code pasted here do that. It will ONLY change color if you click on it. – Delrius Euphoria Jan 31 '21 at 19:47