I have a GUI that contains several frames, each containing multiple labels/entry fields. I am trying to add a "Settings" option that will allow the user to change the background color of all frames & labels. So far I have managed to accomplish the task however with a caveat of a new Tk window popping up with the selected background instead of updating on the current window.
import tkinter as tk
from tkinter import ttk
from tkinter import colorchooser
bg_hex = '#f0f0f0f0f0f0' #default background color
def pick_color():
global bg_hex
bg_color = colorchooser.askcolor()
bg_hex = bg_color[1]
Master().update()
print(bg_hex)
class Master(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side='top', fill='both', expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (HomePage, PageOne, PageTwo, Settings):
frame = F(container, self)
self.frames[F] = frame
frame.config(bg = bg_hex)
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(HomePage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='Home Page', font=('Verdana', 12), bg=bg_hex)
label.pack(pady=5)
button1 = tk.Button(self, text='Page One', command=lambda: controller.show_frame(PageOne))
button1.pack(pady=5, ipadx=2)
button2 = tk.Button(self, text='Page Two', command=lambda: controller.show_frame(PageTwo))
button2.pack(pady=5)
button3 = tk.Button(self, text='Settings', command=lambda: controller.show_frame(Settings))
button3.pack(side='bottom', pady=10)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Label(self, text='Page One', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2, pady=5)
button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
button1.grid()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Label(self, text='Page Two', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2,pady=5)
button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
button1.grid()
class Settings(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Label(self, text='Settings', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2,pady=5)
button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
button1.grid()
button2 = tk.Button(self, text='Choose Background', command= pick_color)
button2.grid()
Master().mainloop()
No errors occur when running the the block of code, but when you select the "Choose Background" button and pick a color, a new Tk window opens with the selected background color instead of updating the current Tk window.
**Updating code to reflect no global variables in hopes that it helps someone else down the road.
I added self.controller = controller
under each Frame class, combined pick_color
and color_update
into 1 function and placed under the Tk class.
def pick_color_bg(self):
bg_color = colorchooser.askcolor()
bg_hex = bg_color[1]
# Loop through pages and contained widgets and set color
for cls, obj in self.frames.items():
obj.config(bg=bg_hex) # Set frame bg color
for widget in obj.winfo_children():
if '!label' in str(widget):
widget.config(bg=bg_hex) # Set label bg color
Lastly, change the Button command to command=self.controller.pick_color_bg
.
With these changes I was able to eliminate the need for global variables.