ttk Entry background colour

后端 未结 3 1803
暖寄归人
暖寄归人 2020-12-16 03:31

How exactly do I change the background colour of an Entry widget from ttk? What I have so far is:

        self.estyle = ttk.Style()
        self.estyle.confi         


        
相关标签:
3条回答
  • 2020-12-16 03:56

    The code below works fine for me on an iMac with Python 3.3.2 and Tcl/Tk 8.5. Also works on a Mac G5 with Python 3.3.2 and Tcl/Tk 8.4. It does NOT work on Windows XP sp3 with Python 3.3.2 and Tcl/Tk 8.5. In the latter case, the entry background, as it did for you, remains stubbornly white.

    Here's why it doesn't change colors in Windows. The example there is also in Tcl.

    https://groups.google.com/forum/#!topic/comp.lang.tcl/RmbiFrTFCdw

    I worked on your nonworking example a little, and it also works on my Mac, except that I get no response from "active" and "focus" in the map. Nothing happens there.

    Some of this is still very mysterious to me. It looks like there is some help here:
    http://wiki.tcl.tk/38127
    http://wiki.tcl.tk/37973
    but it's in Tcl and assumes some knowledge on the part of the viewer just to read it.

    Here's my example that I mentioned at the beginning of this post:

    from tkinter import *
    from tkinter.ttk import *
    
    
    class App(Frame):
        def __init__(self, parent):
            super().__init__(parent)
            s = Style()
            s.configure('Pink.TEntry', background='hot pink')
            self.e1 = Entry(self)
            print("Our entry is of type {}".format(type(self.e1)))
            b = Button(self, text="Switch Styles", command=self.switch)
            self.pink = False
    
            self.e1.pack()
            b.pack()
    
        def switch(self):
            if self.pink:
                print("going white", end="")
                self.e1["style"] = "TEntry"
            else:
                print("going pink", end="")
                self.e1["style"] = "Pink.TEntry"
            self.pink = not self.pink
            print("; style is now {}".format(self.e1["style"]))
    
    root = Tk()
    a = App(root)
    a.pack()
    root.mainloop()
    
    0 讨论(0)
  • 2020-12-16 04:06

    I've figured it out, after a lot of digging. As hard as I had to search to figure this out, I suppose others would benefit from this:

    The standard style applied to ttk.Entry simply doesn't take a fieldbackground option, which would be what changes the colour of the text entry field. The solution is this to create a new element that does respond to the option.

    from tkinter import *
    from tkinter import ttk
    
    root_window = Tk()
    
    estyle = ttk.Style()
    estyle.element_create("plain.field", "from", "clam")
    estyle.layout("EntryStyle.TEntry",
                       [('Entry.plain.field', {'children': [(
                           'Entry.background', {'children': [(
                               'Entry.padding', {'children': [(
                                   'Entry.textarea', {'sticky': 'nswe'})],
                          'sticky': 'nswe'})], 'sticky': 'nswe'})],
                          'border':'2', 'sticky': 'nswe'})])
    estyle.configure("EntryStyle.TEntry",
                     background="green", 
                     foreground="grey",
                     fieldbackground="black")
    entry_v = StringVar()
    entry = ttk.Entry(root_window, style="EntryStyle.TEntry", textvariable=entry_v)
    entry.pack(padx=10, pady=10)
    

    Unfortunately, it appears that the only way to change the border colour is to either give it zero border width and nest it in a frame that acts as its border, or to define a new layout item that uses an image as a border.

    Additionally, note that the only thing the background controls is the very tiny corner space; if you squint closely, you can see a single pixel of green in each corner.

    To use an image as a border, you can do this:

    img2 = PhotoImage("entryBorder", data="""
            R0lGODlhHQAdAOMNAAAAAAQGCAgLERkfLR0mODBFZTFFZTNIajtTezxTez1XgD5XgU
            Fch////////////ywAAAAAHQAdAAAEbHCQg5i9OGt0iFRaKGLKxBgCoK5s6woGc4Cp
            a9+AwFQM7ruYn1AVHP6KRhwyaVsyW87nKioFUKXXZ5a5TXaN32FYOD5eqsAzmlX2tZ
            XqNZGxYATkgAD9wCjUqgIFMgR1I4YZCx4TCYeGCR0DEQA7""")
    
    oestyle = ttk.Style()
    oestyle.element_create("blueborder", "image", "entryBorder",
                                       border=3, sticky="nsew")
    oestyle.layout("OEntryStyle.TEntry",
                   [('Entry.blueborder', {'children': [(
                       'Entry.padding', {'children': [(
                         'Entry.textarea', {'sticky': 'nswe'})],
                          'sticky': 'nswe'})], 'sticky': 'nswe'})])
    oestyle.configure("OEntryStyle.TEntry",
                     background="black",
                      foreground="grey")
    oentry_v = StringVar()
    oentry = ttk.Entry(root_window, style="OEntryStyle.TEntry", textvariable=oentry_v)
    oentry.pack(padx=10, pady=10)
    

    The string of characters is generated by feeding an image of the borders I want as a gif to

    import base64
    
    with open('otherframeBorder.gif', 'rb') as f:
        encoded = base64.encodestring(f.read())
        print(encoded.decode('latin1'))
    
    0 讨论(0)
  • 2020-12-16 04:07

    I liked your approach in using an image, but I think it's a tad tedious to go through the process of importing an image as a base64 encoded string when PhotoImage allows for creating images on the fly. I've expanded on the concept to make a class that handles making such an 'image' to use as a border, and it takes any arguments a regular ttk.Entry widget would. Note that I'm only able to test on Windows 10, but this should be platform independent.

    from tkinter import ttk
    import tkinter as tk
    
    class BorderedEntry(ttk.Entry):
        def __init__(self, root, *args, bordercolor, borderthickness=1,
                     background='white', foreground='black', **kwargs):
            super().__init__(root, *args, **kwargs)
            # Styles must have unique image, element, and style names to create
            # multiple instances. winfo_id() is good enough
            e_id = self.winfo_id()
            img_name = 'entryBorder{}'.format(e_id)
            element_name = 'bordercolor{}'.format(e_id)
            style_name = 'bcEntry{}.TEntry'.format(e_id)
            width = self.winfo_reqwidth()
            height = self.winfo_reqheight()
            self.img = tk.PhotoImage(img_name, width=width, height=height)
            self.img.put(bordercolor, to=(0, 0, width, height))
            self.img.put(background, to=(borderthickness, borderthickness, width -
                         borderthickness, height - borderthickness))
    
            style = ttk.Style()
            style.element_create(element_name, 'image', img_name, sticky='nsew',
                                 border=borderthickness)
            style.layout(style_name,
                         [('Entry.{}'.format(element_name), {'children': [(
                          'Entry.padding', {'children': [(
                              'Entry.textarea', {'sticky': 'nsew'})],
                              'sticky': 'nsew'})], 'sticky': 'nsew'})])
            style.configure(style_name, background=background,
                            foreground=foreground)
            self.config(style=style_name)
    
    root = tk.Tk()
    bentry_red = BorderedEntry(root, bordercolor='red')
    bentry_blue = BorderedEntry(root, bordercolor='blue')
    bentry_red.grid(row=0, column=0, pady=(0, 5))
    bentry_blue.grid(row=1, column=0)
    root.mainloop()
    
    0 讨论(0)
提交回复
热议问题