未显示 Tkinter ttk 背景样式的自定义 [英] Customization of Tkinter ttk background style is not being shown

查看:25
本文介绍了未显示 Tkinter ttk 背景样式的自定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下代码中,show_widget_validity() 函数要么应用自定义样式,该样式仅更改小部件现有样式的背景颜色,要么恢复原始样式.这是一个库例程,因此不能完全控制样式.背景颜色似乎已正确重新配置,如每次更改后条目小部件中报告的背景样式描述所示.但是,小部件的实际背景颜色不会改变.

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. 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.

在使用 Python 2.7 和 3.6 的 Linux 以及使用 Python 2.7 的 Windows 上可以看到这种行为;我还没有测试过其他环境.

This behavior is seen on Linux with Python 2.7 and 3.6, and on Windows with Python 2.7; 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.

使用fieldbackground"代替background"在 Linux 上有效,但在 Windows 上无效,并且不允许在禁用状态下修改背景颜色.

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.

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

推荐答案

您似乎试图通过更改背景使输入字段显示内容的有效性.但是,您每次都试图重新配置样式,这不是正确的方法.相反,您应该根据小部件状态配置动态属性.这就是处理 disabled/!disabledpressed/!pressed 外观更改的方式.ttk 小部件有一个 state 方法,您可以在其中更改许多标志.禁用是按钮类型小部件最常见和按下.另一个是 active 用于当指针悬停在小部件上时小部件改变其外观使其看起来热".为了您的目的,定义了一个方便的 invalid 状态.我们只需要将它添加到小部件样式的样式映射中.由于我们不想影响所有 Entry 小部件,我们可以将当前样式复制到新的 Custom.Entry 样式:

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. The ttk widgets have a state method where you can change a number of flags. disabled is the most common and pressed for button-type widgets. 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:

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

在基于 Tk 的主题上,这足以让小部件的背景根据小部件的无效状态改变颜色.即: entry.state(['invalid']) 将使它使用红色背景.在使用 Windows 和 MacOS 主题等本机绘图元素的主题上,这需要更多的工作.除非本机引擎已经支持 invalid 状态,否则我们不一定会更改本机主题引擎绘制元素的外观.如果没有,那么我们可以通过从基于 Tk 的主题之一克隆新元素来覆盖构成小部件呈现的元素.为了说明这一点,请参见下面的 createCustomEntry 函数,该函数从默认"主题复制 fieldbackground,以便我们可以更改 Windows 上的外观.

On the Tk-based themes this will be sufficient to have the background of the widget change colour according to the widget invalid state. ie: entry.state(['invalid']) will make it use a red background. On themes that use native drawing elements like the Windows and MacOS themes this needs a bit more work. 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. 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.

在 Linux 上它现在看起来像这样:

On Linux it looks like this now:

在 Windows 7 上:

On Windows 7:

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

这篇关于未显示 Tkinter ttk 背景样式的自定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆