Search code examples
pythontkinterttkttkbootstrap

Python Tkinter resize all ttkbootstrap or ttk Button padding for a specific style, applied to all themes


I want to alter padding for all buttons using a particular style (danger). For some reason this change is only applied to the currently active theme, switching themes reverts the Button padding to default. You can see the issue by running the following and switching themes ...

import tkinter as tk
from tkinter import ttk
import ttkbootstrap as tb

def change_theme(theme, style): style.theme_use(theme.lower().replace(" ", ""))

def display_text(label_text, entry_text): label_text.set(entry_text.get())

def setup_ui(style):
    root = style.master

    danger = tb.Style()
    danger.configure('danger.TButton', padding=0) # Why does this only apply to the first theme?

    theme_names_titlecase = [name.replace('_', ' ').title() for name in style.theme_names() if name.lower() in ['darkly', 'simplex']]
    default_theme = 'darkly'
    current_theme = tk.StringVar(value=default_theme.capitalize())
    
    theme_combo = ttk.Combobox(root, textvariable=current_theme, values=theme_names_titlecase, width=50)
    theme_combo.pack(pady=0, side=tk.TOP)
    theme_combo.bind("<<ComboboxSelected>>", lambda e: change_theme(current_theme.get(), style))

    tb.Button(root, text='Text', bootstyle='danger.TButton').pack(side=tk.TOP, padx=0, pady=0)
    tb.Button(root, text='Text', bootstyle='info.TButton').pack(side=tk.TOP, padx=0, pady=0)

    return root

if __name__ == "__main__":
    default_theme = 'darkly'
    style = tb.Style(theme=default_theme)
    root = setup_ui(style)
    root.mainloop()

What I want to know is :

  1. Why are my changes to 'danger.TButton' only applied to the current theme?
  2. Can I fix this so all 'danger.TButton' s have no padding regardless of theme?

Note: using all ttk widgets and Styles has the same result so the answer relates to ttk not ttkbootstrap particularly.

Many thanks.


Solution

  • The main reason is this part and configuring tb.Style() within the setup_ui(). It means that the configuration you're setting for danger.TButton is only associated with the instance of tb.Style(), So,when u try to change your theme, a new instance of tb.Style() is created internally by ttkbootstrap, and your custom configuration is not carried over to this new instance.

    danger = tb.Style()
    danger.configure('danger.TButton', padding=0) # Why does this only apply to the first theme?
    

    By configuring danger.TButton directly on the main instance of tb.Style(), your custom configuration will be applied consistently across all themes. Here is solution for your code:

    import tkinter as tk
    from tkinter import ttk
    import ttkbootstrap as tb
    
    def change_theme(theme, style):style.theme_use(theme.lower().replace(" ", ""))
    
    def display_text(label_text, entry_text):label_text.set(entry_text.get())
    
    def setup_ui(style):
        root = style.master
    
        theme_names_titlecase = [name.replace('_', ' ').title() for name in style.theme_names() if name.lower() in ['darkly', 'simplex']]
        default_theme = 'darkly'
        current_theme = tk.StringVar(value=default_theme.capitalize())
        
        theme_combo = ttk.Combobox(root, textvariable=current_theme, values=theme_names_titlecase, width=50)
        theme_combo.pack(pady=0, side=tk.TOP)
        theme_combo.bind("<<ComboboxSelected>>", lambda e: change_theme(current_theme.get(), style))
    
        tb.Button(root, text='Text', bootstyle='danger.TButton').pack(side=tk.TOP, padx=0, pady=0)
        tb.Button(root, text='Text', bootstyle='info.TButton').pack(side=tk.TOP, padx=0, pady=0)
    
        return root
    
    if __name__ == "__main__":
        default_theme = 'darkly'
        style = tb.Style(theme=default_theme)
    
        style.configure('danger.TButton', padding=0) # Why does this only apply to the first theme?
    
    
        root = setup_ui(style)
        root.mainloop()