简体   繁体   English

未显示 Tkinter ttk 背景样式的自定义

[英]Customization of Tkinter ttk background style is not being shown

In the following code, the show_widget_validity() function either applies a custom style that has just a change to the background color of a widget's existing style, or restores the original style.在以下代码中, show_widget_validity()函数要么应用自定义样式,该样式仅更改小部件现有样式的背景颜色,要么恢复原始样式。 This is a library routine, so does not take complete control of the style.这是一个库例程,因此不能完全控制样式。 The background color appears to be reconfigured correctly, as shown by the background style description reported in the entry widget after each change.背景颜色似乎已正确重新配置,如每次更改后条目小部件中报告的背景样式描述所示。 However, the actual background color of the widget does not change.但是,小部件的实际背景颜色不会改变。

This behavior is seen on Linux with Python 2.7 and 3.6, and on Windows with Python 2.7;在使用 Python 2.7 和 3.6 的 Linux 以及使用 Python 2.7 的 Windows 上可以看到这种行为; I haven't tested other environments.其他环境我没试过。

Any clues as to the cause of this behavior, or code changes necessary to account for it, would be appreciated.任何有关这种行为的原因的线索,或解释它所必需的代码更改,都将不胜感激。

EDIT: Using "fieldbackground" instead of "background" is effective on Linux but not Windows, and does not allow revision of the background color in the disabled state.编辑:使用“fieldbackground”代替“background”在 Linux 上有效,但在 Windows 上无效,并且不允许在禁用状态下修改背景颜色。

try:
    import Tkinter as tk
except:
    import tkinter as tk
try:
    import ttk
except:
    from tkinter import ttk


def show_widget_validity(widget, is_valid):
    invalid_color = "#fff5ff"
    invalid_disabled_color = "#f6f0f6"
    sname = widget["style"] or widget.winfo_class()
    if sname.startswith("Invalid."):
        if is_valid:
            widget['style'] = sname[8:]
    else:
        if not is_valid:
            invname = "Invalid." + sname
            ttk.Style().configure(invname, background=[('disabled', invalid_disabled_color), ('active', invalid_color)])
            # Simpler, but also ineffective:
            #ttk.Style().configure(invname, background=invalid_color)
            widget['style'] = invname

def show_invalid():
    show_widget_validity(entry, False)
    entry_var.set(ttk.Style().lookup(entry["style"] or entry.winfo_class(), "background"))

def show_valid():
    show_widget_validity(entry, True)
    entry_var.set(ttk.Style().lookup(entry["style"] or entry.winfo_class(), "background"))

root = tk.Tk()
root.title("Testing of Style Customization")

appframe = tk.Frame(root, padx=12, pady=12)
appframe.pack(expand=True, fill=tk.BOTH)

entry_var = tk.StringVar()
entry = ttk.Entry(appframe, textvariable=entry_var, width=40, exportselection=False)
entry.grid(row=0, column=0, padx=3, pady=3, sticky=tk.EW)

btnframe = ttk.Frame(appframe)
btnframe.grid(row=1, column=0)
invalid_btn = ttk.Button(btnframe, text="Make invalid", command=show_invalid)
valid_btn = ttk.Button(btnframe, text="Make valid", command=show_valid)
invalid_btn.grid(row=0, column=0, padx=3, pady=3)
valid_btn.grid(row=0, column=1, padx=3, pady=3)

root.mainloop()

It appears you are trying to make an entry field show the validity of the content by changing the background.您似乎正在尝试通过更改背景使输入字段显示内容的有效性。 However you are trying to reconfigure the style each time which is not the right way to go.但是,您每次都试图重新配置样式,这不是正确的方法。 Instead you should configure the dynamic properties according to the widget state.相反,您应该根据小部件状态配置动态属性。 This is how the disabled/!disabled and pressed/!pressed aappearance changes are handled.这就是disabled/!disabled和 press /!pressed外观变化的处理方式。 The ttk widgets have a state method where you can change a number of flags. ttk 小部件有一个 state 方法,您可以在其中更改许多标志。 disabled is the most common and pressed for button-type widgets. disabled是按钮类型小部件最常见和按下的。 The other is active for when the widget changes its appearance when the pointer is hovering over it making it look 'hot'.当指针悬停在小部件上使其看起来“热”时,当小部件改变其外观时,另一个处于活动状态 For your purpose there is a handy invalid state defined.为了您的目的,定义了一个方便的无效状态。 We just need to add it to the style map for the widget style.我们只需要将它添加到小部件样式的样式映射中。 As we don't want to affect all Entry widgets we can copy the current style to a new Custom.Entry style:由于我们不想影响所有 Entry 小部件,我们可以将当前样式复制到新的Custom.Entry样式:

style = ttk.Style()
style.layout("Custom.Entry", style.layout('TEntry'))
style.configure("Custom.Entry", **style.configure('TEntry'))
style.map("Custom.Entry", **style.map('TEntry'))
style.map("Custom.Entry",
    fieldbackground=[(['invalid','!disabled'], '#ff4040'),
                     (['invalid','disabled'], '#ffc0c0')])

entry = ttk.Entry(root, style='Custom.Entry')

On the Tk-based themes this will be sufficient to have the background of the widget change colour according to the widget invalid state.在基于 Tk 的主题上,这足以让小部件的背景根据小部件无效状态改变颜色。 ie: entry.state(['invalid']) will make it use a red background.即: entry.state(['invalid'])将使它使用红色背景。 On themes that use native drawing elements like the Windows and MacOS themes this needs a bit more work.在使用 Windows 和 MacOS 主题等本机绘图元素的主题上,这需要更多的工作。 We can't necessarily change the look of a native themeing engine drawn element unless the native engine supports the invalid state already.除非本机引擎已经支持无效状态,否则我们不一定会更改本机主题引擎绘制元素的外观。 If it does not then we can override the elements that make up the widget presentation by cloning in new ones from one of the Tk-based themes.如果没有,那么我们可以通过从基于 Tk 的主题之一克隆新元素来覆盖构成小部件呈现的元素。 To illustrate this see the createCustomEntry function below which copies the fieldbackground from the 'default' theme so that we can change the look on Windows.为了说明这一点,请参见下面的createCustomEntry函数,该函数从“默认”主题复制 fieldbackground,以便我们可以更改 Windows 上的外观。

On Linux it looks like this now:在 Linux 上,它现在看起来像这样:

在此处输入图片说明

On Windows 7:在 Windows 7 上: 在此处输入图片说明

Modified code修改代码

try:
    import Tkinter as tk
except:
    import tkinter as tk
try:
    import ttk
except:
    from tkinter import ttk

def createCustomEntry(style):
    if 'Custom.Entry.field' not in style.element_names():
        style.element_create('Custom.Entry.field', 'from', 'default')
    if style.theme_use() in ['alt', 'clam', 'default', 'classic']:
        style.layout('Custom.Entry', style.layout('TEntry'))
    else:
        style.layout("Custom.Entry", [
            ("Custom.Entry.field", {'sticky': 'nswe', 'border': '1', 'children': [
                ("Custom.Entry.padding", {'sticky':'nswe', 'children': [
                    ("Custom.Entry.textarea", {'sticky':'nswe'})
                ]})
            ]})
        ])
    style.configure('Custom.Entry', **style.configure('TEntry'))
    style.map('Custom.Entry', **style.map('TEntry'))
    style.map('Custom.Entry',
        fieldbackground=[(['invalid','!disabled'], '#ff4040'),
                            (['invalid','disabled'], '#ffc0c0')])

def show_invalid():
    [w.state(['invalid']) for w in (entry, entry2)]

def show_valid():
    [w.state(['!invalid']) for w in (entry,entry2)]

root = tk.Tk()

# Simple version:
style = ttk.Style()
style.layout("Custom.Entry", style.layout('TEntry'))
style.configure("Custom.Entry", **style.configure('TEntry'))
style.map("Custom.Entry", **style.map('TEntry'))
style.map("Custom.Entry",
    fieldbackground=[(['invalid','!disabled'], '#ff4040'),
                     (['invalid','disabled'], '#ffc0c0')])

#createCustomEntry(style)

root.title("Testing of Style Customization")

appframe = tk.Frame(root, padx=12, pady=12)
appframe.pack(expand=True, fill=tk.BOTH)

entry_var = tk.StringVar()
entry = ttk.Entry(appframe, textvariable=entry_var, width=40,
                  exportselection=False, style="Custom.Entry")
entry.grid(row=0, column=0, padx=3, pady=3, sticky=tk.EW)

entry2 = ttk.Entry(appframe, textvariable=entry_var, width=40,
                   exportselection=False, style="Custom.Entry")
entry2.grid(row=1, column=0, padx=3, pady=3, sticky=tk.EW)
entry2.state(['disabled'])

btnframe = ttk.Frame(appframe)
btnframe.grid(row=2, column=0)
invalid_btn = ttk.Button(btnframe, text="Make invalid", command=show_invalid)
valid_btn = ttk.Button(btnframe, text="Make valid", command=show_valid)
invalid_btn.grid(row=0, column=0, padx=3, pady=3)
valid_btn.grid(row=0, column=1, padx=3, pady=3)

root.mainloop()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM