【问题标题】:Questions on using ttk.Style()?关于使用 ttk.Style() 的问题?
【发布时间】:2018-01-30 09:12:08
【问题描述】:

为了提供 ttk.Style() 类的实例,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()

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

问题 2: 是否需要在 s=ttk.Style() 前加上 self?我得到与 Fig1 相同的结果,有和没有 self 前缀。

问题3:如果我将myWidget类中的'my.TFrame'重命名为'App.TFrame'(这个名字在class App中使用过),class App的背景颜色也会变成紫色(与class myWidget 相同的颜色。鉴于不同类中的变量名称是唯一的,为什么会发生这种情况?

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

图 1

图2

【问题讨论】:

    标签: python tkinter ttk


    【解决方案1】:

    我什么时候需要在ttk.Style() 中声明master 争论?

    可能永远不会,除非tkinter 不支持default root。当您将None 作为主节点传递时,主节点将成为Tk 类的当前root 实例。

    masterroot 或任何tk-widget)的主要目的是将tk 的实例委托给Style,以便Style 能够执行@987654334 @相关的命令。

    不多不少。


    是否需要在s=ttk.Style() 前加上self

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

    否则,如果您希望保留引用,则以 self. 为前缀是有意义的


    如果我将 myWidget 类中的 my.TFrame 重命名为 App.TFrame(此名称在 class App 中使用),class App 的背景颜色也变为紫色(与 class myWidget 相同的颜色。为什么考虑到不同类中的变量名是唯一的,会发生这种情况吗?

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


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

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

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

    _tkinter.TclError: Layout AppTFrame not found
    

    【讨论】:

    • 我认为值得一提的是ttk_frame_widget.winfo_class()返回'TFrame'
    • 您能否详细说明“当您将None 作为master 传递时,master 将成为Tk 类的当前根实例。” 使用我的脚本?对于class App,我将self.s = ttk.Style() 读作ttk.Frame.s(或a.s)是ttk.Style。根据ttk.pyttk.Style() 是定义self.tk = self.master.tk,其中self.mastertkinter._default_roottkinter.Tk()。我认为tkinter.Tk() 将创建一个新的根,而tkinter._default_root 将引用a 的根,这也是tkinter.Tk()。对于class myWidget,它的主人是a,这是一个class App。那么这里会发生什么?
    • @Sun Bear, ttk.Style().master 可以是任何东西(Tk、Toplevel、Frame、任何小部件),它包含对tk 的引用。在您的情况下,您将None 隐式传递为master,因此master 变为tkinter._default_root,即您的root。这很容易通过print(root is tk._default_root) 进行检查。就是这样,Tk 的新实例没有空间了。
    【解决方案2】:

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

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

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

    问题 4:
    查找名称仅覆盖默认样式。
    只要它们没有属性,它们就不会覆盖任何东西。
    此“分配”导致 tcl 调用,并且在 Tkinter / ttk 源(用于 BaseWidget 类)中没有特定的错误处理。

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

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

    【讨论】:

      猜你喜欢
      • 2016-07-13
      • 2020-12-09
      • 2020-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-05
      相关资源
      最近更新 更多