Customization of Tkinter ttk background style is not being shown

前端 未结 1 1606
傲寒
傲寒 2021-01-22 06:44

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

相关标签:
1条回答
  • 2021-01-22 07:25

    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:

    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()
    
    0 讨论(0)
提交回复
热议问题