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!!

5
  • 1
    You dont have to give different names, make a list of colors, and then loop through the colors. Commented Jan 31, 2021 at 13:08
  • 1
    Check this Commented Jan 31, 2021 at 13:20
  • @CoolCloud Mmmh you mean that whenever I click a specific button I could just update the color list? I will try to implement this idea Commented Jan 31, 2021 at 15:41
  • @JacksonPro oh, great! I haven't seen it! thanks a lot Commented Jan 31, 2021 at 15:42
  • @CoolCloud that would be awesome!!! Commented Jan 31, 2021 at 16:26

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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 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.".
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 That's weird, by no means shall the code pasted here do that. It will ONLY change color if you click on it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.