Related
I am new to Python and am using Tkinter to create a basic GUI for a game.
I have got some buttons an image and numerous labels to work, but I am wondering..
What is the best way to get a large, initially blank text box on the GUI, and how would I go about having the text box update on the press of a "next" button.
I need it to scroll through text with each press, showing the next relevant line.
The text that is shown will depend on the choice(s) that are made, so variables like current location etc are necessary.
The aim is to make a simple game that allows you to read through the text with the Next button, then make choices etc, a mostly text-based adventure game.
I'll post what I have already below. Yes I know it's terrible, this is my first try so don't judge too harshly on my mistakes.
Any tips, advice or methods are much appreciated.
Some things to note:
My quit button isn't working yet, not too sure why.
I would love to figure out how to store variables based on what the user inputs, via an input box that can be prompted when an input is required from the user.
Also, happy to start from scratch if it's easier.
# Widgets:
import sys #Imports the system commands which makes it possible to terminate the program
import time #Imports the time module to allow delays in script
import os #Imports os to make it possible to play music/sound
import random #Imports random variable to allow for random number generation
import pickle #allows the game state to be saved.
from tkinter import * # imports tkinter
import tkinter as tk
from tkinter import *
from tkinter import messagebox
from textwrap import wrap # imports text wrap
#base variables for testing
character_Gold = 1
character_Health = 100
character_base_Health = 100
character_Strength = 10
character_Dexterity = 10
character_Constitution = 10
character_Intelligence = 10
character_Wisdom = 10
character_Charisma = 10
character_base_Perception = 10
#Text Boxes
#Base Geometry and image
window = Tk()
TitleScreen = PhotoImage( file = 'test.gif' )
window.geometry("1100x600")
#defines
def close():
#win.destroy()
window.quit()
imgLbl = Label( window, image = TitleScreen )
label1 = Label( window, relief = 'groove', width = 4)
label2 = Label( window, relief = 'groove', width = 4)
label3 = Label( window, relief = 'groove', width = 4)
label4 = Label( window, relief = 'groove', width = 4)
label5 = Label( window, relief = 'groove', width = 4)
label6 = Label( window, relief = 'groove', width = 4)
label7 = Label( window, relief = 'groove', width = 4)
label8 = Label( window, relief = 'groove', width = 4)
label9 = Label( window, relief = 'groove' , width = 3)
label10 = Label( window, relief = 'groove' , width = 3)
label11 = Label( window, relief = 'groove' , width = 3)
label12 = Label( window, relief = 'groove' , width = 3)
label13 = Label( window, relief = 'groove' , width = 3)
label14 = Label( window, relief = 'groove' , width = 3)
label15 = Label( window, relief = 'groove' , width = 3)
label16 = Label( window, relief = 'groove' , width = 3)
TextLabel = Label( window, relief = 'groove', width = 50)
LocationLabel = Label( window, relief = 'groove', width = 18)
LocationBase = Label( window, relief = 'groove', width = 13)
NextBtn = Button( window )
MainText = Label( window, relief = 'groove', width = 40, height = 8)
QuitButton = Button(window, text="Quit",command=close)
# Geometry:
imgLbl.grid( row = 1, column = 1 , rowspan = 24 ) # Change Rowspan here to increase number of Rows and shrink gaps
label1.grid( row = 1, column = 2, padx = 10 )
label2.grid( row = 1, column = 4, padx = 10 )
label3.grid( row = 1, column = 5, padx = 10 )
label4.grid( row = 1, column = 6, padx = 10 )
label5.grid( row = 1, column = 7, padx = 10 )
label6.grid( row = 1, column = 8, padx = 10)
label7.grid( row = 1, column = 9, padx = 10)
label8.grid( row = 1, column = 10, padx = 5)
label9.grid( row = 2, column = 2, padx = (1, 10)) #Health
label10.grid(row = 2, column = 4, padx = 10) #STR
label11.grid(row = 2, column = 5, padx = 10) # DEX
label12.grid(row = 2, column = 6, padx = 10) # CON
label13.grid(row = 2, column = 7, padx = 10) #INT
label14.grid(row = 2, column = 8, padx = 10) #WIS
label15.grid(row = 2, column = 9, padx = 10) # CHA
label16.grid(row = 2, column = 10, padx= 10) # gold
TextLabel.grid( row = 26, column = 1, padx = 10) # instruction label
LocationLabel.grid( row = 2, column = 11, padx = 10) # dynamic location label, changes
LocationBase.grid( row = 1, column = 11, padx = 10) # location text only not dynamic
MainText.grid( row = 30, column = 1, padx = 10) # main text box
QuitButton.grid(row = 34, column = 14 , padx = 10) #Quit Button
NextBtn.grid( row = 26, column = 2, columnspan = 4 )
# Static Properties
window.title( ' The Adventure ')
NextBtn.configure( text = 'Next')
Current_Location = "Title Screen"
#DynamicProperties. BD is button facelift level, bg is colour.
label1.configure( text = 'HP:', bg = 'Red' )
label1.configure( bd = 8, relief=RAISED)
label2.configure( text = 'STR:', bg = 'Orange')
label2.configure( bd = 8, relief=RAISED)
label3.configure( text = 'DEX:', bg = 'Purple')
label3.configure( bd = 8, relief=RAISED)
label4.configure( text = 'CON:', bg = 'Green')
label4.configure( bd = 8, relief=RAISED)
label5.configure( text = 'INT:', bg = 'light green')
label5.configure( bd = 8, relief=RAISED)
label6.configure( text = 'WIS:', bg = 'white')
label6.configure( bd = 8, relief=RAISED)
label7.configure( text = 'CHA:', bg = 'light blue')
label7.configure( bd = 8, relief=RAISED)
label8.configure( text = 'GP:', bg = 'yellow')
label8.configure( bd = 8, relief=RAISED)
label9.configure( text = character_Health)
label9.configure( bd = 6, relief=RAISED)
label10.configure( text = character_Strength)
label10.configure( bd = 6, relief=RAISED)
label11.configure( text = character_Dexterity)
label11.configure( bd = 6, relief=RAISED)
label12.configure( text = character_Constitution)
label12.configure( bd = 6, relief=RAISED)
label13.configure( text = character_Intelligence)
label13.configure( bd = 6, relief=RAISED)
label14.configure( text = character_Wisdom)
label14.configure( bd = 6, relief=RAISED)
label15.configure( text = character_Charisma)
label15.configure( bd = 6, relief=RAISED)
label16.configure( text = character_Gold)
LocationLabel.configure( text = Current_Location, fg = 'White', bg = 'Black')
LocationLabel.configure( bd = 8, relief=RAISED) # raises the button up to look 3d
LocationBase.configure( text = "Your Location:", fg = "black", bg = "White") #"location" text above tab that changes actual location
LocationBase.configure( bd = 8, relief=RAISED)
TextLabel.configure( text = "Welcome To The Adventure. Click 'Next' to begin!") # instruction label
TextLabel.configure( bd = 2, relief=RAISED)
MainText.configure( text = '''This is the large box where \n the main game text should go.''', fg = "Black", bg = "White") # use \n for a NEWLINE
MainText.configure( bd = 10, relief=RAISED)
NextBtn.configure( bd = 8, relief=RAISED) # raises next button
QuitButton.configure( bd = 2, relief=RAISED, text="Quit",command=close)
#Sustain Window:
window.mainloop()
Original Code:
import tkinter as tk
from tkinter import ttk
win = tk.Tk()
home_frame = tk.Frame(win)
home_frame.grid(column = 0, row = 0)
home_frame.config(bg = 'blue', relief = 'raised')
logo = tk.Label(home_frame)
logo.grid(column = 0, row = 0)
logo.config(text = 'Widget', font = ('Helvetica', 30), fg = 'red')
win.config(bg ='white')
win.mainloop()
Note that:
home_frame.config(bg = 'blue', relief = 'raised')
From this, I would expect the background of the frame to turn blue, yet it doesn't. It remains grey.
Output:
As far as I'm concerned, tk.Frame() does have bg as an option.
Explanation:
If we do the following changes to logo background, we get the following:
Code:
logo.config(text = 'Widget', font = ('Helvetica', 30), bg = 'green', fg = 'red')
Also, adding another widget, like an entry widget, to home_frame will yield this:
Code:
search = tk.Entry(home_frame)
search.grid(column = 1, row = 0)
From the above, we can tell logo covers home_frame background.
Question:
How would you make logo background not cover home_frame background when logo background is not defined?
By this I mean:
logo.config(text = 'Widget', font = ('Helvetica', 30), fg = 'red') #No background option included.
In this case, I set logo background to blue. I want no bg option included in logo.config(). But still display an output as above.
I am attempting to create a relatively simple survey like form in Tkinter, and I'm relatively new to the GUI framework. I'm having real issues trying to figure out why there are so many inconsistencies, especially when working with grid placement+frames+multiple widgets in same row. Especially this specific example. I'm tying together all my questions into a single frame, and it seems to work out... sort of half. Though the rows seem to cooperate nicely, the columns are where the whole thing gets erupted.
qframe1 = Frame(question, bg='black')
qframe1.grid(row=1, padx = 20, sticky = W)
q1l = Label(qframe1, text = 'Question 1: How often do you eat at Mcdonalds?', font = ('Calibri', 14), bg = 'azure')
q1l.grid(columnspan = 4, pady = 5, sticky = W)
q1 = StringVar()
q1.set('None')
q1r1 = Radiobutton(qframe1, text = 'Everyday!', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Always')
q1r1.grid(row=1, column = 0, pady = 5, sticky = W)
q1r2 = Radiobutton(qframe1, text = 'Sometimes', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Sometimes')
q1r2.grid(row=1, column = 1, pady = 5, sticky = W)
q1r3 = Radiobutton(qframe1, text = 'Not Frequently', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Infrequent')
q1r3.grid(row=1, column = 2, pady = 5, sticky = W)
q1r4 = Radiobutton(qframe1, text = 'Never', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Never')
q1r4.grid(row=1, column = 3, pady = 5, sticky = W)
This is the bare code for the section that's messing up.
Also, I have made sure that it's not the length of each radio button that is causing the issue. When I change the text of the radio buttons, they still get placed in the same irregular positions.
Here's the code for another section of the trivia.
q2l = Label(qframe1, text = 'Question 2: What meal do you normally order?', font = ('Calibri', 14), bg = 'azure')
q2l.grid(row=2, columnspan = 4, pady = 5, sticky = W)
q2 = StringVar()
q2.set('None')
q2r1 = Radiobutton(qframe1, text = 'Fries', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Fries')
q2r1.grid(row=3, column = 0, pady = 5, sticky = W)
q2r2 = Radiobutton(qframe1, text = 'Hamburgers', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Hamburgers')
q2r2.grid(row=3, column = 1, pady = 5, sticky = W)
q2r3 = Radiobutton(qframe1, text = 'Chicken Nuggets', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Chicken Nuggets')
q2r3.grid(row=3, column = 2, pady = 5, sticky = W)
q2r4 = Radiobutton(qframe1, text = 'Coffee', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Coffee')
q2r4.grid(row=3, column = 3, pady = 5, sticky = W)
This again causes an irregular spacing. But this time, the spacing is completely different from the radio buttons in question 1. And rinse and repeat with every new question set of radio buttons.
There are no issues with the buttons on the right side. Perhaps it's because they're aligned in rows and not columns which are causing the spacing issue.
bframe = Frame(question, bg='black')
bframe.grid(row=1, padx = 20, sticky = E)
audioq1 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q1audio)
audioq1.grid(ipadx = 5, pady = 20)
audioq2 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q2audio)
audioq2.grid(row = 1, ipadx = 5, pady = 20)
audioq3 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q3audio)
audioq3.grid(row = 2, ipadx = 5, pady = 20)
audioq4 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q4audio)
audioq4.grid(row = 3, ipadx = 5, pady = 20)
audioq5 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q5audio)
audioq5.grid(row = 4, ipadx = 5, pady = 20)
Any help would be greatly appreciated!
If, as mentioned in the comments, "weight isn't necessarily the problem", the placement of the radiobuttons can be realized using pack instead of grid.
This gives something like this (on a mac):
If you want a more evenly placed buttons to fill the available width, you can achieve this with grid:
I also rewrote a portion of the code to make it easier to add questions to the form. Each question is now in its own frame, allowing for more flexibility.
import tkinter as tk
class QFrame(tk.Frame):
id = 1
def __init__(self, master, question):
self.master = master
super().__init__(self.master)
self.id = QFrame.id
QFrame.id += 1
self.q = tk.StringVar()
self.q.set('None')
self.question, self.choices = question
self.q_label = tk.Label(self, text=f'Question {self.id}: {self.question}')
self.q_label.pack(expand=True, anchor=tk.W)
self.choose = []
for idx, choice in enumerate(self.choices):
txt, value = choice
qr = tk.Radiobutton(self, text=txt, variable=self.q, value=value)
self.choose.append(qr)
qr.pack(side=tk.LEFT)
class App(tk.Tk):
def __init__(self, questions):
self.questions = questions
super().__init__()
for question in questions:
self.qframe = QFrame(self, question)
self.qframe.pack(fill=tk.X)
q1 = ['How often do you eat at Mcdonalds?',
(('Everyday!', 'Always'),
('Sometimes', 'Sometimes'),
('Not Frequently', 'Infrequent'),
('Never', 'Never'))]
q2 = ['What meal do you normally order?',
(('Fries!', 'Fries'),
('Hamburgers', 'Hamburgers'),
('Chicken Nuggets', 'Chicken Nuggets'),
('Coffee', 'Coffee'))]
q3 = ['how large is your usual party?',
(('alone!', 'alone'),
('two', 'two'),
('less than 5', 'less than 5'),
('5 or more', '5 or more'))]
questions = [q1, q2, q3]
app = App(questions)
app.mainloop()
The code for grid geometry manager:
class QFrame(tk.Frame):
id = 1
def __init__(self, master, question):
self.master = master
super().__init__(self.master)
self.id = QFrame.id
QFrame.id += 1
self.q = tk.StringVar()
self.q.set('None')
self.question, self.choices = question
self.grid_rowconfigure(0, weight=1)
for idx in range(4):
self.grid_columnconfigure(idx, weight=1)
self.q_label = tk.Label(self, text=f'Question {self.id}: {self.question}')
self.q_label.grid(row=0, column=0, columnspan=4, sticky="w")
self.choose = []
for idx, choice in enumerate(self.choices):
txt, value = choice
qr = tk.Radiobutton(self, text=txt, variable=self.q, value=value)
self.choose.append(qr)
qr.grid(row=1, column=idx, columnspan=1, sticky="ew")
it is my first time using tkinter. I have an entry box on the first window, and I created radio buttons on different windows. The problem is that they are already selected before I click any of them. How can I change all buttons to be deselected?
I am not sure if my codes are right or not.
from tkinter import *
from tkinter import messagebox
class SortingHat:
# Constructor
def __init__(self):
# Create main window
self.__main_window = Tk()
self.__main_window.geometry('300x200')
self.__main_window.title('Sorting Hat')
bg_image = PhotoImage(file = "HarryPotterlogo1.png")
bg_label = Label(self.__main_window, image = bg_image, bd=0)
bg_label.grid(row=1, column=0)
bg_label.image = bg_image
self.__first_label = Label(self.__main_window, text = \
'Enter Your Name.', fg = 'gold', bg = 'brown4')
self.__first_label.grid(row=2, column=0)
# Create Entry box
self.__entry = Entry(self.__main_window)
self.__entry.bind('<Return>', self.entry_action)
self.__entry.grid(row=3, column=0)
self.__button = Button(self.__main_window, text = 'Enter', \
fg = 'white', bg = 'black', command = self.action)
self.__button.grid(row=3, column=0, sticky = 'E')
self.__next_button = Button(text = 'Next', height = 1, width = 10, \
fg = 'black', bg = 'white', command = self.next1)
self.__next_button.grid(row=4, column=0, sticky ='W')
# Create OK button and Quit button
self.__quit_button = Button(text='Quit', height = 1, width = 10, \
command=self.__main_window.destroy)
self.__quit_button.grid(row=4, column=0, sticky = 'E')
def next1(self):
self.__new_window1 = Tk()
self.__new_window1.configure(bg = 'brown4')
self.__new_window1.title('Question 1')
self.__second_label = Label(self.__new_window1, text = \
'What is your favorite color? (10 points)', \
fg = 'gold', bg = 'brown4')
self.__second_label.grid(row=0, column=0, sticky = 'W')
# Question Radiobutton
self.__rb_var1 = IntVar()
# Create First question Radiobutton widgets
self.__rb1 = Radiobutton(self.__new_window1, text='a. Red and Gold', fg ='red', \
bg = 'brown4', variable=self.__rb_var1, value = 1)
self.__rb2 = Radiobutton(self.__new_window1, text='b. Green and Silver', fg = 'green', \
bg = 'brown4', variable=self.__rb_var1 , value = 2)
self.__rb3 = Radiobutton(self.__new_window1, text='c. Yellow and Black', fg = 'gold', \
bg = 'brown4', variable=self.__rb_var1, value = 3)
self.__rb4 = Radiobutton(self.__new_window1, text='d. Blue and Bronze', fg = 'blue', \
bg = 'brown4', variable=self.__rb_var1, value = 4)
self.__rb1.grid(row=1, column=0)
self.__rb2.grid(row=2, column=0)
self.__rb3.grid(row=3, column=0)
self.__rb4.grid(row=4, column=0)
I want all buttons to be deselected when the program starts.
The problem is that you shouldn't be opening a new Tk() window, instead you should be creating a new Toplevel() window, that will fix the issue.
So instead of self.__new_window1 = Tk() use self.__new_window1 = Toplevel()
Try this.
def next1(self):
self.__new_window1 = Toplevel()
self.__new_window1.configure(bg = 'brown4')
self.__new_window1.title('Question 1')
# Question Radiobutton
self.__rb_var1 = IntVar()
# Create First question Radiobutton widgets
self.__rb1 = Radiobutton(self.__new_window1, text='a. Red and Gold', fg ='red', bg = 'brown4', variable=self.__rb_var1, value = 1)
self.__rb2 = Radiobutton(self.__new_window1, text='b. Green and Silver', fg='green', bg='brown4', variable=self.__rb_var1, value=2)
self.__rb3 = Radiobutton(self.__new_window1, text='c. Yellow and Black', fg='gold', bg='brown4', variable=self.__rb_var1, value=3)
self.__rb4 = Radiobutton(self.__new_window1, text='d. Blue and Bronze', fg='blue', bg='brown4', variable=self.__rb_var1, value=4)
self.__rb1.grid(row=1, column=0)
self.__rb2.grid(row=2, column=0)
self.__rb3.grid(row=3, column=0)
self.__rb4.grid(row=4, column=0)
Try
self.__rb1.deselect()
self.__rb2.deselect()
self.__rb3.deselect()
self.__rb4.deselect()
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()
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)
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.