Python Tkinter 调整所有 ttkbootstrap 或 ttk 按钮的填充,以特定样式应用于所有主题

2 投票
2 回答
34 浏览
提问于 2025-04-12 15:47

我想要改变所有按钮的内边距,特别是那种叫“danger”的样式。但是奇怪的是,这个改动只在当前主题下有效,换个主题后,按钮的内边距又变回默认的了。你可以通过运行以下代码并切换主题来看到这个问题...

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()

我想知道的是:

  1. 为什么我对“danger.TButton”的修改只在当前主题下有效?
  2. 有没有办法让所有“danger.TButton”的内边距都没有,不管主题是什么?

注意:使用所有ttk小部件和样式的结果都是一样的,所以这个问题和ttk有关,而不是特别针对ttkbootstrap。

非常感谢。

2 个回答

2

这个样式显然只在程序启动时使用的主题上生效。

所以当你把主题换成非默认的主题时,就需要重新调整边距。在这个例子中,为了解决这个问题,我需要修改'change_theme'这个函数。

def change_theme(theme, style): 
    style.theme_use(theme.lower().replace(" ", ""))
    style.configure('danger.TButton', padding=0)

这样一来,每次换新主题的时候,边距的调整就会重新应用上。

0

主要原因在于这部分内容,以及在 setup_ui() 函数中配置 tb.Style()。这意味着你为 danger.TButton 设置的配置只和 tb.Style() 的这个实例有关。所以,当你尝试更改主题时,ttkbootstrap 会在内部创建一个新的 tb.Style() 实例,而你的自定义配置不会被带到这个新实例上。

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

通过直接在 tb.Style() 的主实例上配置 danger.TButton,你的自定义配置就会在所有主题中一致地应用。以下是你代码的解决方案:

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()

撰写回答