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