如何在不影响其他元素中找到的相同选项的情况下更改 *ttk stylename* 中元素的选项?

How to change the option of an element in a *ttk stylename* without affecting the same option found in other elements?

如何更改 ttk 样式名称 中某个元素的选项而不影响其他元素中的相同选项?

我发布了一个脚本 here,tkinter 程序员可以在其中公开所有元素及其选项,涉及给定的 ttk 样式名称。例如。对于 stylename my.Vertical.TScrollbar,你可以看到这个 stylename 有 3 个元素,每个元素都有一个类似的选项 background

Stylename = my.Vertical.TScrollbar
Layout    = [('Vertical.Scrollbar.trough', {'children': [('Vertical.Scrollbar.uparrow', {'side': 'top', 'sticky': ''}), ('Vertical.Scrollbar.downarrow', {'side': 'bottom', 'sticky': ''}), ('Vertical.Scrollbar.thumb', {'sticky': 'nswe', 'expand': '1'})], 'sticky': 'ns'})]

Element(s) = ['Vertical.Scrollbar.trough', 'Vertical.Scrollbar.uparrow', 'Vertical.Scrollbar.downarrow', 'Vertical.Scrollbar.thumb']

Vertical.Scrollbar.trough      options: ('-borderwidth', '-troughcolor', '-troughrelief')
Vertical.Scrollbar.uparrow     options: ('-background', '-relief', '-borderwidth', '-arrowcolor', '-arrowsize')
Vertical.Scrollbar.downarrow   options: ('-background', '-relief', '-borderwidth', '-arrowcolor', '-arrowsize')
Vertical.Scrollbar.thumb       options: ('-orient', '-width', '-relief', '-background', '-borderwidth')

tkinter 文档教导可以使用 .configure 方法更改 stylename 的选项。以下是说明该问题的脚本。当我发出命令

style.configure('my.Vertical.TScrollbar',
                background=color1, troughcolor=color2,
                arrowcolor=color3, borderwidth=10, width=40)

thumb、uparrow、downarrow元素的背景全部变为蓝色,4个元素的borderwidth全部变为10像素宽。如果我需要更好的控制,例如仅更改 thumb 元素的背景或仅更改 thumb 元素的 borderwidth,我该怎么做?

测试脚本:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import tkinter as tk
import tkinter.ttk as ttk

class App(ttk.Frame):

    def __init__(self, parent=None, *args, **kwargs):
        ttk.Frame.__init__(self, parent, *args, **kwargs)

        color1 = 'blue'
        color2 = 'light green'
        color3 = 'white'

        style=ttk.Style()
        style.configure('my.Vertical.TScrollbar',
                        background=color1, troughcolor=color2,
                        arrowcolor=color3, borderwidth=10, width=40)
        style.map('my.Vertical.TScrollbar',
            background=[('active',color1),('!active',color1)],
            arrowcolor=[('active',color3),('!active',color3)])

        vscrollbar = ttk.Scrollbar(self,
                                   orient='vertical',
                                   style='my.Vertical.TScrollbar')
        vscrollbar.pack(fill='y', side='right', expand='false')
        canvas = tk.Canvas(self,
                           bd=0,
                           highlightthickness=0,
                           yscrollcommand=vscrollbar.set)
        canvas.pack(side='left', fill='both', expand='true')
        vscrollbar.config(command=canvas.yview)


if __name__ == "__main__":
    root=tk.Tk()
    app = App(root)
    app.pack(side='left', fill='both', expand='true')
    root.mainloop()

ttk 中的元素使用 flyweight pattern 并且本身不存储值。相反,样式包含与小部件布局关联的元素使用的所有值。因此,所有使用 background 配置值的元素都会从当前小部件样式中读取相同的值。在支持自定义颜色的情况下,使用不同的选项名称。因此,从 troughcolor 选项读取槽背景颜色。对于按钮,按钮本身有一个 字段 ,因为背景用于聚焦环下方按钮后面的区域(如果可见)。

如果您真的想获得更好的控制,您要么必须编写一个新的主题元素引擎,要么可以使用 image element engine to define a new element using images. There are some tcl examples of image based themes imported to github 如果您想尝试一下。然而,ttk 主题的要点是尝试尽可能多地使用系统提供的外观,避免让程序员自定义 UI。作为一般规则,您进行的定制越多,就越有可能在其他人的系统上看起来很糟糕。