关于使用 ttk.Style() 的问题?

Questions on using ttk.Style()?

为了使 ttk.Style() class 的实例可用,tkinter guide 中说明了语法为:

import ttk
s=ttk.Style()

在 IDLE 中输入这些命令时,我注意到 ttk.Style() 实际上有一个预定义的参数,即

s=ttk.Style(master=None)

我写了下面的测试脚本:

import tkinter as tk
import tkinter.ttk as ttk


class App(ttk.Frame):

    def __init__(self, parent):
        ttk.Frame.__init__(self, parent, style='App.TFrame', relief=tk.SUNKEN,
                           border=10)
        self.parent = parent
        self.__createStyle()
        self.__createWidgets()

    def __createStyle(self):
        self.s = ttk.Style()
        self.s.configure('.', background='orange', border=100)
        self.s.configure('App.TFrame', background='yellow')
        self.s.configure('Btn.TButton', background='light blue', border=10)

    def __createWidgets(self):
        self._label = ttk.Label(self.parent, text='Label packed in root.')
        self._label.pack()
        self._btn = ttk.Button(self, style='Btn.TButton', command=self.__click,
            text='Button packed inside self or class App, which is a ttk.Frame')
        self._btn.pack()

    def __click(self):
        return print('Left Button Clicked!')



class myWidget(ttk.Frame):

    def __init__(self, parent):
        ttk.Frame.__init__(self, parent, style='my.TFrame', relief=tk.GROOVE,
                           border=10)
        self.parent = parent
        self.__createStyle()
        self.__createWidgets()

    def __createStyle(self):
        self.s = ttk.Style()
        self.s.configure('my.TFrame', background='purple')
        self.s.configure('my.TLabel', background='pink', border=10)
        self.s.configure('my.TEntry', foreground='red', border=10)

    def __createWidgets(self):
        self._label = ttk.Label(self, style='my.TLabel',
            text='myWidget Label packed in self or class myWidget, which is a ttk.Frame.')

        self._label.pack()
        self._entry = ttk.Entry(self, style='my.TEntry')
        self._entry.pack()



if __name__ == "__main__":
    root = tk.Tk()
    root.title('Test Style')
    root.geometry('500x150')
    a = App(root)
    a.pack(fill='both', expand=1)
    b = myWidget(a)
    b.pack()

    root.mainloop()

问题一:什么时候需要声明ttk.Style()中的master论点?例如。在上面的脚本中,如果我在 class myWidget 中写入 self.s = ttk.Style()self.s = ttk.Style(master=self.parent),我会得到相同的结果(见图 1)。

问题2:是否需要在s=ttk.Style()前加上self?使用和不使用 self 前缀,我得到与图 1 所示相同的结果。

问题3:如果我在class myWidget中重命名'my.TFrame''App.TFrame'(这个名字在class App ), class App 的背景颜色也变成了紫色(与 class myWidget 颜色相同)。为什么会这样,因为不同 class 中的变量名是唯一的?

问题4:名称'App.TFrame''my.TFrame'在声明之前被调用了。为什么 python 或 tkinter 没有抱怨或给出错误但允许脚本执行?

图一

图2

只有部分答案,但我想@Bryan Oakley 迟早会启发我们。

问题三:
如果您在 MyWidget Class 中使用 "App.TFrame" 而不是 "my.TFrame",则会覆盖预定义的样式属性。

简短示例:
如果您设置样式 "TFrame",所有 "TFrame"( == Tkinter.Frame/ttk.Frame ) 实例都会受到影响。
这有时也称为 "root-Style" .
如果您定义另一个 "somename.TFrame" 并将其设置为一个框架类型的对象,它将是根据 "somename.TFrame".

的样式

问题四:
查找名称仅覆盖默认样式。
只要它们没有属性,它们就不会覆盖任何东西。
此 "assignment" 导致 tcl 调用,并且在 Tkinter / ttk 源(在 BaseWidget class 中使用)内部没有特定的错误处理。

我只能说tcl不会在这里抛出错误,但我自己不是tcl专家。

我希望这至少能有所帮助。

When do I need to declare the master arguement in ttk.Style()?

可能永远不会,除非 tkinter 不支持 default root。当您将 None 作为 master 传递时,master 将成为 Tk class.

的当前 root 实例

masterroot 或任何 tk-widget)的主要目的是将 tk 的实例委托给 Style,因此Style 可以执行 Tcl 相关命令。

不多也不少。


Is there a need to prefix s=ttk.Style() with self?

这取决于您的要求。在您的代码上下文中 - self 没有意义,因为您正在 __createStyle 函数的范围内设置样式。

否则,如果您希望保留引用,可以使用 self.

作为前缀

If I rename my.TFrame in class myWidget as App.TFrame(this name was used in class App), the background colour of the class App changed to purple color too (same color as class myWidget. Why did this happened given that variable name in different classes are unique?

因为两个 classes 共享相同的框架样式,因此颜色相同。创建的样式是一个全局的东西,它可以在运行时改变,所有相关的小部件都会对这些改变做出反应。


The names App.TFrame and my.TFrame were called before it was declared. Why did python or tkinter not complain or give an error but allowed the script to execute?

为什么你认为他们应该这样做?当您传递类似 <any_sensible_name>.<any_relevant_and_existing_basestyle> 的内容时,ttk 知道您需要基本样式的变体,因此它会隐式创建一个继承所有基本属性的样式。

用更无意义的东西试试这个技巧,比如你当前的不带点的样式名称 (ttk.Frame.__init__(..., style='AppTFrame', ...)),这会给你想要的错误:

_tkinter.TclError: Layout AppTFrame not found