簡體   English   中英

未顯示 Tkinter ttk 背景樣式的自定義

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

在以下代碼中, show_widget_validity()函數要么應用自定義樣式,該樣式僅更改小部件現有樣式的背景顏色,要么恢復原始樣式。 這是一個庫例程,因此不能完全控制樣式。 背景顏色似乎已正確重新配置,如每次更改后條目小部件中報告的背景樣式描述所示。 但是,小部件的實際背景顏色不會改變。

在使用 Python 2.7 和 3.6 的 Linux 以及使用 Python 2.7 的 Windows 上可以看到這種行為; 其他環境我沒試過。

任何有關這種行為的原因的線索,或解釋它所必需的代碼更改,都將不勝感激。

編輯:使用“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()

您似乎正在嘗試通過更改背景使輸入字段顯示內容的有效性。 但是,您每次都試圖重新配置樣式,這不是正確的方法。 相反,您應該根據小部件狀態配置動態屬性。 這就是disabled/!disabled和 press /!pressed外觀變化的處理方式。 ttk 小部件有一個 state 方法,您可以在其中更改許多標志。 disabled是按鈕類型小部件最常見和按下的。 當指針懸停在小部件上使其看起來“熱”時,當小部件改變其外觀時,另一個處於活動狀態 為了您的目的,定義了一個方便的無效狀態。 我們只需要將它添加到小部件樣式的樣式映射中。 由於我們不想影響所有 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')

在基於 Tk 的主題上,這足以讓小部件的背景根據小部件無效狀態改變顏色。 即: entry.state(['invalid'])將使它使用紅色背景。 在使用 Windows 和 MacOS 主題等本機繪圖元素的主題上,這需要更多的工作。 除非本機引擎已經支持無效狀態,否則我們不一定會更改本機主題引擎繪制元素的外觀。 如果沒有,那么我們可以通過從基於 Tk 的主題之一克隆新元素來覆蓋構成小部件呈現的元素。 為了說明這一點,請參見下面的createCustomEntry函數,該函數從“默認”主題復制 fieldbackground,以便我們可以更改 Windows 上的外觀。

在 Linux 上,它現在看起來像這樣:

在此處輸入圖片說明

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM