There are at least four ways I can think of to do this: using the option database, passing dictionaries of options, using ttk, and creating custom classes.
Using the option database
There are several ways to accomplish what you want. The original support for this is based on the X11 windowing system option database. Every widget has a class, and every class can have it's options set.
You do this through the option_set
method of the root window (as well as option_readfile
), specifying a pattern, and the default value.
Example:
import tkinter as tk
root = tk.Tk()
root.option_add("*Font", "Helvetica 8 bold")
root.option_add("*Background", "blue")
root.option_add("*Foreground", "white")
button1 = tk.Button(root, text="Hello", command=lambda: print("Hello"))
button2 = tk.Button(root, text="World", command=lambda: print("world"))
button1.pack()
button2.pack()
root.mainloop()
Note: you must do this after creating the root window but before creating any widgets you want to be affected by this.
How to use the option database can be a bit complex, though it does make it possible to compute entire themes if you're willing to take the time to do it. One of the best -- though oldest -- descriptions comes straight from one of the core developers of tcl/tk here: http://www.cs.man.ac.uk/~fellowsd/tcl/option-tutorial.html. This requires a little bit of mental gymnastics to translate the tcl/tk code to python/tkinter, but the python docs describe how to do that (see Mapping basic tk into tkinter
Using dictionaries.
You can indeed pass in a dictionary of options, with a couple of small caveats. This dictionary must be the first argument after the parent, and it must be before any other keyword arguments.
Example:
import tkinter as tk
basic_style = {'background': 'blue', 'foreground': 'white', 'font': 'Helvetica 8 bold'}
root = tk.Tk()
button1 = tk.Button(root, basic_style, text="Hello", command=lambda: print("Hello"))
button2 = tk.Button(root, basic_style, text="World", command=lambda: print("world"))
button1.pack()
button2.pack()
root.mainloop()
I don't if this is documented anywhere, but you can see that it's supported by looking at the actual tkinter code.
Using the ttk widgets
"ttk" stands for "themed tk". The whole idea was to re-implement tk with the ability to apply themes. ttk has most of the same widgets as tkinter, plus a few that it doesn't have (for example, the treeview widget).
Example:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
style = ttk.Style()
style.configure('Custom.TButton',
background="blue", foreground="white",
font='Helvetica 8 bold')
button1 = ttk.Button(root, text='Hello', style='Custom.TButton')
button2 = ttk.Button(root, text='Hello', style='Custom.TButton')
button1.pack()
button2.pack()
root.mainloop()
Unfortunately, there's almost no good documentation on how to configure the themes. It's a bit confusing and non-standard, but the results can be quite polished if you're willing to put in the effort.
The best resource for learning how to create themes is in the Styles and Themes section of tkdocs.com
Creating custom classes
Finally, a fourth option is to create custom classes. Your classes can inherit from the built-in classes and force options to be set if not provided.
Example:
import tkinter as tk
class CustomButton(tk.Button):
def __init__(self, *args, **kwargs):
kwargs.setdefault("background", "blue")
kwargs.setdefault("foreground", "white")
kwargs.setdefault("font", "Helvetica 8 bold")
super().__init__(*args, **kwargs)
root = tk.Tk()
button1 = CustomButton(root, text="Hello", command=lambda: print("Hello"))
button2 = CustomButton(root, text="World", command=lambda: print("world"))
button1.pack()
button2.pack()
root.mainloop()