When it comes to designing a user interface, a good color scheme is essential. A well-designed color scheme not only looks great but also improves the user experience by making the interface more intuitive and user-friendly. One of the most popular color schemes is the Dark mode, which is easy on the eyes and reduces eye strain. In this tutorial, we’ll show you how you can go about creating your own Dark Theme in the Python GUI library, Tkinter.
Building the Base Application
Before we dive into creating our dark theme, let’s create a basic application using Tkinter. The application will include a label, a button, an entry field, a check button, and a combo box. These do not have any overall purpose, they are just here so that we can see how their look changes when we create our dark mode.
import tkinter as tk
from tkinter import ttk
class Application(ttk.Frame):
def __init__(self, master=None):
super().__init__(master, style="Dark.TFrame")
self.master = master
self.pack(expand = True, fill = tk.BOTH)
self.create_widgets()
def create_widgets(self):
self.label = ttk.Label(self, text="Hello, dark world!")
self.label.pack(padx=10, pady=10)
self.button = ttk.Button(self, text="Click me!",
command=self.on_click)
self.button.pack(padx=10, pady=10)
self.entry = ttk.Entry(self, width=20)
self.entry.pack(padx=10, pady=10)
self.checkbutton_var = tk.BooleanVar(value=True)
self.checkbutton = ttk.Checkbutton(self, text="Check me!",
variable=self.checkbutton_var)
self.checkbutton.pack(padx=10, pady=10)
self.combobox = ttk.Combobox(self, values=["Option 1", "Option 2", "Option 3"])
self.combobox.pack(padx=10, pady=10)
def on_click(self):
self.label.configure(text="Button clicked!")
root = tk.Tk()
root.title("Dark Mode Tkinter Application")
root.geometry("300x300")
app = Application(master=root)
app.mainloop()
This gives us the following output.
Introduction to Styles
Styles are an essential aspect of the Tkinter library. They allow us to define a set of visual properties that can be applied to one or more widgets. When we create a widget, we can specify a style to use, which will determine its appearance.
However, tkinter does not actually provide these styles by default. These are introduced as a part of a submodule in tkinter, called “ttk”. The ttk styles provide an extensive set of customizations, including gradient backgrounds, themes, and other advanced visual effects. This library is included within tkinter by default, so no need to install anything.
In this tutorial, we’ll be using the ttk styles for creating our very own Dark theme in Tkinter. We’ll define a set of visual properties that we’ll apply to our widgets to give them a dark and sleek appearance.
To use ttk styles in Tkinter, you first need to create a ttk.Style()
object. Once you have the style object, you can define your styles using a dictionary of configuration options, where the keys represent the widget class and the values are dictionaries of configuration options for that widget.
For example, to change the background and foreground colors of all widgets to black and white respectively, you can use the following code:
style = ttk.Style()
style.configure(".", background="black", foreground="white")
The first parameter in the configure method is the name of the widget you want to change the styles for. Passing in a “.” means you want to apply these styles to all widgets. You can also do it for each widget individually. There are default styles in Tkinter for every widget. Each of these styles has a name, which we need to use in the first parameter of the configure()
method.
It’s quite to figure out the name of a style. Just take the name of a widget, and attach a “T” before it. So for example, if we want to change the label’s style, we will do this:
style.configure("TLabel", font=("Arial", 12, "bold"), foreground="red")
This concludes our basic tutorial on ttk styles. Let us proceed to the development of a dark theme using these styles.
Creating a Dark Theme in Tkinter
Creating a “theme” is a bit different from just using styles. It is the more advanced version basically. A theme consists of a collection of styles, which define the look and appearance of all the widgets. We will now create a “theme” in Tkinter (using ttk).
We will start off small by just defining a few styles to help you understand it easily. The below theme contains the global styles (applicable on all), the Label styles, and the Button styles. All we have done so far, is change the background and foreground colors (Foreground is the text color usually).
dark_theme = {
".": {
"configure": {
"background": "#2d2d2d", # Dark grey background
"foreground": "white", # White text
}
},
"TLabel": {
"configure": {
"foreground": "white", # White text
}
},
"TButton": {
"configure": {
"background": "#3c3f41", # Dark blue-grey button
"foreground": "white", # White text
}
},
}
This however, was not technically a theme. It’s just a dictionary. To create a theme, we need to use the theme_create()
function and pass the above dictionary into its settings
parameter.
style = ttk.Style()
style.theme_create('dark', parent="clam", settings=dark_theme)
style.theme_use('dark')
We also need to use the theme_use()
method to actually switch from the default theme to the new theme we just created.
Another interesting thing you might observe, is that we have a parameter called parent="clam"
. Clam is the name of another prebuilt theme available in Tkinter. I made this theme the parent theme, because of some issues that can occur with the default theme on Windows and MacOS when changing styles. Having a parent theme means that all styles are inherited from that parent theme, but overridden if defined in the child theme.
Let’s see how our application currently looks with the styles we have defined so far.
As you can see, there are some issues here. The background of the application is the right color, and the same goes for the label and button. But the combo-box and entry widget have a few issues. The backgrounds of these widgets should be “grey”, not white. Secondly, the dropdown menu for the Combobox should also be “grey” with white text. The arrow on the combobox should be white, not black.
These are many small changes we need to make. We introduced the styles partially so you would have an idea what kind of problems can occur, and what needs to be changed.
Finalizing our Dark Theme
We will now present the complete code which rectifies all these issues.
import tkinter as tk
from tkinter import ttk
class Application(ttk.Frame):
def __init__(self, master=None):
super().__init__(master, style="Dark.TFrame")
self.master = master
self.pack(expand = True, fill = tk.BOTH)
self.create_widgets()
def create_widgets(self):
self.label = ttk.Label(self, text="Hello, dark world!")
self.label.pack(padx=10, pady=10)
self.button = ttk.Button(self, text="Click me!",
command=self.on_click)
self.button.pack(padx=10, pady=10)
self.entry = ttk.Entry(self, width=20)
self.entry.pack(padx=10, pady=10)
self.checkbutton_var = tk.BooleanVar(value=True)
self.checkbutton = ttk.Checkbutton(self, text="Check me!",
variable=self.checkbutton_var)
self.checkbutton.pack(padx=10, pady=10)
self.combobox = ttk.Combobox(self, values=["Option 1", "Option 2", "Option 3"])
self.combobox.pack(padx=10, pady=10)
def on_click(self):
self.label.configure(text="Button clicked!")
root = tk.Tk()
root.title("Dark Mode Tkinter Application")
root.geometry("300x300")
dark_theme = {
".": {
"configure": {
"background": "#2d2d2d", # Dark grey background
"foreground": "white", # White text
}
},
"TLabel": {
"configure": {
"foreground": "white", # White text
}
},
"TButton": {
"configure": {
"background": "#3c3f41", # Dark blue-grey button
"foreground": "white", # White text
}
},
"TEntry": {
"configure": {
"background": "#2d2d2d", # Dark grey background
"foreground": "white", # White text
"fieldbackground" : "#4d4d4d",
"insertcolor": "white",
"bordercolor" : "black",
"lightcolor" : "#4d4d4d",
"darkcolor" : "black",
}
},
"TCheckbutton": {
"configure": {
"foreground": "white", # White text
"indicatorbackground" : "white",
"indicatorforeground" : "black",
}
},
"TCombobox": {
"configure": {
"background": "#2d2d2d", # Dark grey background
"foreground": "white", # White text
"fieldbackground" : "#4d4d4d",
"insertcolor": "white",
"bordercolor" : "black",
"lightcolor" : "#4d4d4d",
"darkcolor" : "black",
"arrowcolor" : "white"
},
},
}
root.option_add("*TCombobox*Listbox*Background", "black")
root.option_add("*TCombobox*Listbox*Foreground", "white")
style = ttk.Style()
style.theme_create('dark', parent="clam", settings=dark_theme)
style.theme_use('dark')
app = Application(master=root)
app.mainloop()
This gives us the following output.
As you can see, it looks alot better. This is still not a complete implementation, as there are other widgets which will require minor tweaks, just like the combobox did for example. But this is a good start if you want to build your dark theme. Here is a link to a website which contains all the possible styles, and some guidelines on how to customize them.
This marks the end of the “Creating your own Dark Theme with Tkinter” Tutorial. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.