Create & Apply Custom Theme in ttkbootstrap for Tkinter


How to Create a Custom Theme in Tkinter using ttkbootstrap

Tutorial Breakdown:


Introduction

ttkbootstrap is a powerful library that enhances Tkinter by providing modern UI themes. This tutorial demonstrates how to create and apply a custom theme in ttkbootstrap, enabling you to modify styles according to your application's requirements.

Creating a Custom Theme 🔝

To define a custom theme, we use a JSON file containing color, font, and layout settings. Here is a sample JSON file, apply it, and use it to style widgets like Labels and Buttons.

{
    "name": "mytheme",
    "type": "dark",
    "colors": {
        "primary": "#1f3d7a",
        "secondary": "#00aaff",
        "success": "#28a745",
        "info": "#FF6103",
        "warning": "#ffc107",
        "danger": "#dc3545",
        "light": "#f8f9fa",
        "dark": "#343a40",
        "bg": "#121212",
        "fg": "#e0e0e0",
        "selectbg": "#444444",
        "selectfg": "#ffffff"
    }
}
  • name: Specifies the theme name.
  • colors: Defines the primary, secondary, border, and other colors.
  • fonts: Sets default and heading font styles.
  • layout: Defines the UI layout type.
List of Color codes to use

📥 1. Importing Required Libraries

# Import required libraries  
import ttkbootstrap as ttk  
from ttkbootstrap.constants import *  
from ttkbootstrap.style import ThemeDefinition  
import json  # Load theme from a JSON file  

📂 2. Loading and Validating the Custom Theme

# Load the custom theme JSON file  
theme_path = "E:\\testing\\my_custom_theme.json"  # Update with your file path  

with open(theme_path, "r") as f:  
    custom_theme_data = json.load(f)  # Load JSON as a dictionary  

# Required theme properties  
required_keys = ["name", "colors", "fonts", "layout"]  
filtered_theme_data = {key: custom_theme_data[key] for key in required_keys if key in custom_theme_data}  

# Ensure essential color properties exist  
required_colors = ["border", "inputfg", "inputbg", "active"]  
for color in required_colors:  
    if color not in filtered_theme_data["colors"]:  
        filtered_theme_data["colors"][color] = "#000000"  # Default black if missing  

🎨 3. Registering and Applying the Custom Theme

# Convert dictionary to ThemeDefinition object  
custom_theme = ThemeDefinition(**filtered_theme_data)  

# Initialize ttkbootstrap style  
style = ttk.Style()  
style.register_theme(custom_theme)  # Register theme  
style.theme_use(custom_theme.name)  # Apply theme  

🖥️ 4. Creating the GUI with Custom Theme

# Create main window  
my_w = ttk.Window()  
my_w.geometry("500x300")  # Width and height  
my_w.title("www.plus2net.com : ttkbootstrap custom theme")  

# Label with custom theme  
label = ttk.Label(my_w, text="Hello, Custom Theme!", bootstyle="info")  
label.pack(pady=20)  

# Button with theme styling  
button = ttk.Button(my_w, text="Click Me", bootstyle="primary",  
    command=lambda: label.config(text="Button Clicked!"))  
button.pack()  

# Run the application  
my_w.mainloop()  

Simple custom theme: Label with button

Ttkbootstrap
The custom theme JSON file is loaded and stored as a dictionary. Only essential theme properties (name, colors, fonts, and layout) are extracted. Missing required color fields (border, inputfg, inputbg, active) are assigned a default black color to ensure a valid theme definition.

The filtered theme data is converted into a ThemeDefinition object. A ttk.Window is then created with a specified size and title. A Style object is initialized to register and apply the custom theme to the application

import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.style import ThemeDefinition
import json 

# Load the custom theme JSON file
theme_path = "E:\\testing\\my_custom_theme.json"  # Update the correct file path
with open(theme_path, "r") as f:
    custom_theme_data = json.load(f)  # Load JSON data into a dictionary

# Extract and validate required theme properties
required_keys = ["name", "colors", "fonts", "layout"]
filtered_theme_data = {key: custom_theme_data[key] for key in required_keys if key in custom_theme_data}

# Ensure the 'colors' dictionary has all required fields for a valid theme
required_colors = ["border", "inputfg", "inputbg", "active"]
for color in required_colors:
    if color not in filtered_theme_data["colors"]:
        filtered_theme_data["colors"][color] = "#000000"  # Default to black if missing

# Convert the dictionary into a ThemeDefinition object
custom_theme = ThemeDefinition(**filtered_theme_data)

# Create the main window with the custom theme
my_w = ttk.Window()
my_w.geometry("500x300")  # Set window dimensions (width x height)
my_w.title("www.plus2net.com : ttkbootstrap Custom Theme")  # Set window title

# Initialize the style, register, and apply the custom theme
style = ttk.Style()
style.register_theme(custom_theme)  # Register the theme
style.theme_use(custom_theme.name)  # Apply the custom theme

# Create a Label Widget with custom theme styling
label = ttk.Label(my_w, text="Hello, Custom Theme!", bootstyle="info")
label.pack(pady=20)  # Add vertical spacing

# Create a Button Widget styled with the custom theme
button = ttk.Button(
    my_w, text="Click Me", bootstyle="primary", 
    command=lambda: label.config(text="Button Clicked!")  # Change label text on click
)
button.pack()

# Run the main event loop
my_w.mainloop()

Enhancing the Custom Theme with Interactive Widgets

In this section, we extend our custom ttkbootstrap theme by integrating interactive widgets such as a Meter, Floodgauge, and Button. This demonstrates how the theme applies to different UI components while showcasing real-time interaction using linked widgets. The Meter and Floodgauge dynamically update together, and a button starts an animated gauge effect. 🚀
Ttkbootstrap
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.style import ThemeDefinition
import json 

# Load the custom theme JSON file
theme_path = "F:\\testing\\my_custom_theme.json" # update the path 
with open(theme_path, "r") as f:
    custom_theme_data = json.load(f)  # Load JSON as a dictionary

# Extract and validate required theme properties
required_keys = ["name", "colors", "fonts", "layout"]
filtered_theme_data = {key: custom_theme_data[key] for key in required_keys if key in custom_theme_data}

# Ensure the 'colors' dictionary has all required fields
required_colors = ["border", "inputfg", "inputbg", "active"]
for color in required_colors:
    if color not in filtered_theme_data["colors"]:
        filtered_theme_data["colors"][color] = "#000000"  # Default black if missing

# Convert the dictionary to a ThemeDefinition object
custom_theme = ThemeDefinition(**filtered_theme_data)

# Create the main window
my_w = ttk.Window()
my_w.geometry("500x300")  # Width and height
my_w.title("www.plus2net.com : ttkbootstrap custom theme")  # Adding a title
# Register and apply the custom theme
style = ttk.Style()
style.register_theme(custom_theme)
style.theme_use(custom_theme.name)

# Configure grid layout
my_w.columnconfigure(0, weight=1)
my_w.columnconfigure(1, weight=1)
my_w.rowconfigure(0, weight=1)
my_w.rowconfigure(1, weight=1)

# Add an Interactive Meter Widget
meter = ttk.Meter(
    my_w, 
    bootstyle="success", 
    interactive=True, 
    amountused=40, 
    amounttotal=100, 
    subtext="Interactive Meter"
)
meter.grid(row=0, column=0, padx=10, pady=10)

# Add a Floodgauge Widget
fg = ttk.Floodgauge(
    my_w, 
    bootstyle="info", 
    mask="Progress {}%", 
    variable=meter.amountusedvar,  # Link Meter and Floodgauge
    maximum=100, 
    length=200
)
fg.grid(row=0, column=1, padx=10, pady=10)

# Button to Start Floodgauge Animation
def start_gauge():
    fg.start()  # Start Floodgauge animation

btn = ttk.Button(my_w, text="Start Gauge", bootstyle="primary", command=start_gauge)
btn.grid(row=1, column=0, columnspan=2, pady=10)

# Label
label = ttk.Label(my_w, text="Welcome to My Custom Theme", bootstyle="info")
label.grid(row=2, column=0, columnspan=2, pady=10)

my_w.mainloop()

TTK Creator: Customize Your Tkinter Themes 🔝

Using TTK Creator to generate and save custom theme

TTK Creator is a GUI tool that allows users to design and customize themes for ttkbootstrap. With an intuitive interface, users can adjust colors, styles, and widget appearances to create personalized themes for Tkinter applications.

Installing TTK Creator

To use TTK Creator, install ttkbootstrap if you haven't already:

pip install ttkbootstrap

Launching TTK Creator

Run the following command in your terminal or command prompt:

python -m ttkcreator

This will open the graphical interface where you can modify and preview themes.

Saving and Using Custom Themes

  • Once satisfied with the design, save the theme. It will be stored inside the file user.py
  • It will be stored in C:\Users\YourUsername\.ttkbootstrap\themes\ (Windows) or ~/.ttkbootstrap/themes/ (Linux/macOS).
  • Use the theme in your Tkinter projects by setting themename when initializing ttk.Window.

Example: Applying a Custom Theme

import ttkbootstrap as ttk

root = ttk.Window(themename="my_theme_v1")
root.mainloop()

With TTK Creator, you can effortlessly enhance the appearance of your Tkinter applications with custom themes!

Using a Database to Store Theme Settings Instead of JSON 🔝

To store theme settings in MySQL or SQLite Database

While JSON files are commonly used to store UI theme settings, using a database like SQLite or MySQL provides more flexibility and scalability. A database allows dynamic updates, centralized storage, and multi-user access without modifying static files. By fetching theme settings directly from a database, we can easily switch themes, customize UI elements, and even allow users to personalize their application interface in real time. 🚀

Creating the Theme Settings Database

The first script initializes the database by creating a table to store theme settings and inserting sample data. Using SQLAlchemy, we execute raw SQL queries to ensure compatibility across different databases. By simply uncommenting the MySQL connection line, the same script can be used to store theme settings in a MySQL database instead of SQLite, making it easier to scale and manage across multiple environments. 🔄
import os
from sqlalchemy import create_engine, text

# 🔹 Define Database Path (Same Directory)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(BASE_DIR, "theme.db")

# 🔹 Create Database Engine
engine = create_engine(f"sqlite:///{DB_PATH}")
# engine = create_engine("mysql+pymysql://username:password@localhost/theme_db")  # MySQL Connection
# 🔹 Create Themes Table
with engine.connect() as conn:
    conn.execute(text("""
        CREATE TABLE IF NOT EXISTS themes (
            name TEXT PRIMARY KEY,
            primary_color TEXT,
            secondary_color TEXT,
            font_family TEXT,
            font_size INTEGER
        )
    """))
    conn.commit()

# 🔹 Sample Theme Data (Multiple Themes)
themes = [
    ("dark_theme", "#343A40", "#6C757D", "Arial", 12),
    ("light_theme", "#F8F9FA", "#E9ECEF", "Calibri", 11),
    ("custom_theme", "#007BFF", "#6C757D", "Helvetica", 10)
]

# 🔹 Insert Theme Data (Avoid Duplicate Entries)
with engine.connect() as conn:
    for theme in themes:
        conn.execute(text("DELETE FROM themes WHERE name = :name"), {"name": theme[0]})
        conn.execute(text("INSERT INTO themes VALUES (:name, :primary, :secondary, :font, :size)"), 
                     {"name": theme[0], "primary": theme[1], "secondary": theme[2], "font": theme[3], "size": theme[4]})
    conn.commit()

print("✅ Themes inserted successfully!")
Here is the code to to create one simple application using above database. Note that both files are to be kept in same directory as we are using os module to read the path and apply the same.
import os
from sqlalchemy import create_engine, text
import ttkbootstrap as ttk
from ttkbootstrap.constants import *

# 🔹 Define Database Path (Same Directory)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(BASE_DIR, "theme.db")

# 🔹 Create Database Engine
engine = create_engine(f"sqlite:///{DB_PATH}")  # SQLite Connection
# engine = create_engine("mysql+pymysql://username:password@localhost/theme_db")  # MySQL Connection

# 🔹 Fetch Theme Data (Select Theme Name Here)
theme_name = "custom_theme"  # Change to "dark_theme" or "light_theme"
with engine.connect() as conn:
    result = conn.execute(text("SELECT * FROM themes WHERE name = :name"), {"name": theme_name}).fetchone()

# 🔹 If Theme Exists, Apply It
if result:
    theme_name, primary_color, secondary_color, font_family, font_size = result

    # 🔹 Create Main Window
    my_w = ttk.Window()
    my_w.geometry("400x200")
    my_w.title("www.plus2net.com : SQLite Theme Example")

    # 🔹 Apply Custom Theme
    style = ttk.Style()
    style.configure("TButton", font=(font_family, font_size), background=primary_color)
    style.configure("TLabel", font=(font_family, font_size), background=secondary_color)

    # 🔹 Create Label
    label = ttk.Label(my_w, text="Hello, Custom Theme!", bootstyle="info")
    label.pack(pady=20)

    # 🔹 Create Button
    button = ttk.Button(my_w, text="Click Me", bootstyle="primary",
                        command=lambda: label.config(text="Button Clicked!"))
    button.pack()

    my_w.mainloop()

else:
    print("❌ No theme data found in database.")

Conclusion

In this tutorial, we learned how to:

  • Create a custom ttkbootstrap theme using a JSON file or Database table ( MySQL or SQLite ) .
  • Apply the custom theme to a Tkinter application.
  • Integrate interactive widgets like Meter and Floodgauge.

By following these steps, you can customize the look and feel of your Tkinter applications effortlessly!

Learn More on ttkbootstrap
Subscribe to our YouTube Channel here


Subscribe

* indicates required
Subscribe to plus2net

    plus2net.com







    Python Video Tutorials
    Python SQLite Video Tutorials
    Python MySQL Video Tutorials
    Python Tkinter Video Tutorials
    We use cookies to improve your browsing experience. . Learn more
    HTML MySQL PHP JavaScript ASP Photoshop Articles FORUM . Contact us
    ©2000-2024 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer