I'm trying to write an application with the ability to change the theme from dark to light. i use forest theme from rdbende. When loading only one theme via root.tk.call("source", "forest-dark.tcl")
, everything is displayed correctly, but if after that another second theme is loaded root.tk.call("source", "forest-light.tcl")
, the window background and combobox fill will be repainted in its color, even if it do not apply. (only apply style.theme_use("forest-dark")
).
I tried to recolor comboboxes in the event function via root.option_add('*TCombobox*Listbox*Background', bg_color)
, but it only works the first time, and then it's just ignored.
Here is my code:
from tkinter import *
from tkinter import ttk
root = Tk()
root.geometry('550x500')
# Create a style
style = ttk.Style(root)
# Import the tcl file
root.tk.call("source", "forest-dark.tcl")
# Import the tcl file
root.tk.call("source", "forest-light.tcl")
dark_mode = True
theme_dark = "forest-dark"
theme_light = "forest-light"
# Set the theme with the theme_use method
style.theme_use(theme_dark)
# create a Frame widget with the custom style
frame = ttk.Frame(root, width=200, height=200)
frame.pack(expand=1, fill=BOTH)
def change_mode():
global dark_mode
dark_mode = not dark_mode
style.theme_use(theme_dark if dark_mode else theme_light)
_style = ttk.Style()
bg_color = _style.lookup('TFrame', 'background')
fg_color = _style.lookup('TLabel', 'foreground')
print(f"{bg_color}-{fg_color}")
root.option_add('*TCombobox*Listbox*Background', bg_color)
root.option_add('*TCombobox*Listbox*Foreground', fg_color)
root.option_add('*TCombobox*Listbox*selectBackground', fg_color)
root.option_add('*TCombobox*Listbox*selectForeground', bg_color)
button = ttk.Button(frame, text='mode', command=change_mode)
button.pack()
combo = ttk.Combobox(frame, width=40, justify=CENTER, values=[
'value1', 'value1', 'value1', 'value1', 'value1', 'value1', 'value1', 'value1'])
combo.pack()
root.mainloop()
Found a way to change themes through Tcl interpreter: here
Finally code:
from tkinter import *
from tkinter import ttk
root = Tk()
root.geometry('550x500')
# Create a style
style = ttk.Style(root)
# Import the tcl file
root.tk.call("source", "forest-dark.tcl")
# Import the tcl file
root.tk.call("source", "forest-light.tcl")
dark_mode = True
theme_dark = "forest-dark"
theme_light = "forest-light"
# Set the theme with the theme_use method
style.theme_use(theme_dark)
# create a Frame widget with the custom style
frame = ttk.Frame(root, width=200, height=200)
frame.pack(expand=1, fill=BOTH)
class MyCombo(ttk.Combobox):
def __init__(self, master, **kwargs):
ttk.Combobox.__init__(self, master, **kwargs)
self._master = master
self._change_color()
self._master.bind("<<ThemeChanged>>", self._change_color)
def _change_color(self, *args):
_style = ttk.Style()
# Get current Frame bg and Label fg
bg_color = _style.lookup('TFrame', 'background')
fg_color = _style.lookup('TLabel', 'foreground')
# Create a new background for the combobox a little lighter if it's a dark theme, a little darker if it's light
is_dark_mode = True if int(str(bg_color).replace("#", ''), 16) < int(str(fg_color).replace("#", ''), 16) else False
new_bg_color = "#404040" if is_dark_mode else "#F8F8F8"
# Set colors
self._master.tk.eval('[ttk::combobox::PopdownWindow {}].f.l configure -background {} -foreground {}'.format(self, new_bg_color, fg_color))
def change_mode():
global dark_mode
dark_mode = not dark_mode
style.theme_use(theme_dark if dark_mode else theme_light)
button = ttk.Button(frame, text='Change mode', command=change_mode)
button.pack()
combo = MyCombo(frame, width=40, justify=CENTER, values=[
'value1', 'value1', 'value1', 'value1', 'value1', 'value1', 'value1', 'value1'])
combo.pack()
root.mainloop()