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 styl
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')
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.
On Linux it looks like this now:
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()