1

I'm trying to do something simple -- change the fill color of a ttk Entry widget in a Python script to show an invalid entry. My question is not specifically how to do this (though I'd like to know!) but rather how to figure out how to do this given generally available documentation and resources.

I've read everything I can find about ttk and styles (including several StackOverflow questions), and while the process of applying styles looks straightforward if you know all the keywords/options you need, I can't figure out how to approach the problem if the keywords/options are unknown.

For an accepted answer to this question, I'd like to see the process of figuring out how to set the background color of a ttk Entry widget, that leads to a solution that works with Python. I want to learn to fish.

Watusimoto
  • 1,773
  • 1
  • 23
  • 38
  • You may want to take a look [at this](https://stackoverflow.com/a/65464537/13629335). Its true ttk related to tkinter isnt good documented. – Thingamabobs Nov 08 '21 at 20:07
  • I recommend going through the content on tkdocs.com – Bryan Oakley Nov 08 '21 at 20:08
  • @Bryan As I remember, tkdocs.com is a good starting point but not a full description. For example, I remember having a hard time to figure out that you can get a layout for the items in the layout of the widget as well. – Thingamabobs Nov 08 '21 at 20:14
  • 1
    @Atlas435: correct, it is not a full description, but it provides a good starting point. It has a [whole section](https://tkdocs.com/tutorial/styles.html) on understanding the basics of theming. – Bryan Oakley Nov 08 '21 at 20:19

1 Answers1

1

First of all, SO isnt designed to substitude regular documentation or tutorials. But I agree with the OP that ttk lack a little bit of a overall description.

import tkinter as tk
import tkinter.ttk as ttk
from ttkthemes import ThemedStyle

ttk isnt imported by tkinter itself and needs to be explicitly imported. It is recommended to import it as ttk to avoid name conflicts.

style = ttk.Style(root)
style.theme_use('default')

The style class is designed to manipulate the styling database. Themes are always used, even if you didnt defined one. A list of themes can be found here or here. Or you can define your own with theme_create, like here

button = ttk.Button(root, text='abc')
button.pack(expand=True, fill='both')
style_name = button.winfo_class()

Every ttk.widget has the styling option and can be adressed by .winfo_class

style.layout(style_name,
             [('Button.border', {'sticky': 'nswe', 'border': '1', 'children': [
                 ('Button.focus', {'sticky': 'nswe', 'children': [
                     ('Button.padding', {'sticky': 'nswe', 'children': [
                         ('Button.label', {'sticky': 'nswe'})
                         ]})
                     ]})
                 ]}
               )])

Manipulating the layout gives you trivial options like to have a button on the right or left side. But in addition with element_create it can be a powerfull tool. Like Scrollbar.thumb, Scrollbar.trough, Downarrow.

print(style.layout(style_name))
print('Layout')

Get the current layout and try this with different themes and may mix them together with element_create or try to use the vsapi under windows/visual_styles_api.

print(style.element_options('Button.label'))
print('label')
print(style.map(style_name))
print('map')

To simply configure some colors I have found, and linked in my answer, a list of colors that can be configured but dosent mean they necessary have an effect.

Options that are available don't necessarily have an effect, and it's not an error to modify a bogus option.

For your entry background configure ttk::style configure TEntry -fieldbackground color that can also be found in the list of colors.

widget = ttk.Entry(root, text='abc', style='My.TEntry')
style.configure("My.TEntry",
                 foreground="grey",
                 fieldbackground="black")

Example:

import tkinter as tk
import tkinter.ttk as ttk
from ttkthemes import ThemedStyle

bg_color = '#091424'
fg_color = '#ffcfcf'
arrow_bg = '#8c101e'
border_color = '#db994c'
highlight_color = '#372940'
pressed_color = arrow_bg

root = tk.Tk()
style = ttk.Style(root)
style.theme_use('clam')#background/arrowcolor

frame =tk.Frame(root)
frame.pack()

widget = ttk.Spinbox(frame, text='abc', style="my.TSpinbox")
widget.pack(expand=True, fill='both')

style_name = widget.winfo_class()

style.layout('my.TSpinbox',
             [('Spinbox.field', {'sticky': 'nswe', 'children': [
                 ('Spinbox.background', {'sticky': 'nswe', 'children': [
                     ('Spinbox.padding', {'sticky': 'nswe', 'children': [
                         ('Spinbox.innerbg', {'sticky': 'nswe', 'children': [
                             ('Spinbox.textarea', {'expand': '1', 'sticky': 'nswe'})
                             ]})
                         ]}),
                     ('Spinbox.uparrow', {'side': 'top', 'sticky': 'nse'}),
                     ('Spinbox.downarrow', {'side': 'bottom', 'sticky': 'nse'})
                     ]})
                 ]})
              ])



style.configure('my.TSpinbox',
                background=bg_color,
                foreground=fg_color,
                arrowcolor=arrow_bg,
                arrowsize=20,
                relief="raised",
                bordercolor=border_color,
                lightcolor='red',
                darkcolor='green',
                troughcolor='pink',
                )

style.map("my.TSpinbox",
          arrowcolor = [('pressed', pressed_color),
                        ('active', highlight_color),
                        ('disabled', '#ffffff')])


print(style.layout(style_name))
print('Layout')
print(style.element_options('Spinbox.field'))
print('field')
print(style.element_options('Spinbox.downarrow'))
print('downarrow')
print(style.element_options('Spinbox.uparrow'))
print('uparrow')
print(style.element_options('Spinbox.padding'))
print('padding')
print(style.element_options('Spinbox.background'))
print('background')
print(style.element_options('Spinbox.textare'))
print('textarea')
print(style.element_options('Spinbox.innerbg'))
print('innerbg')
print(style.map(style_name))
print('map')

Additional References:

Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • Before posting this, I had looked at both the documentation and tutorial links you provided. They were helpful in learning about how styling works in general, and of course the specific illustrations were useful for those specific cases, but neither is a good general reference to what is possible and how. – Watusimoto Nov 19 '21 at 08:08
  • @Watusimoto thats exactly what I stated in the first place. See *But I agree with the OP that ttk lack a little bit of a overall description.*. Therefore I spent some time to gather these information to give you an idea of what is possible. I updated my answer with additional references. – Thingamabobs Nov 19 '21 at 09:17
  • The style.layout() seems to show how the various elements and subelements are organized. I had intuited this, but it was helpful that you made it explicit. In order to set the background color of the spinbox's text area, I can look at the list of color/options you linked to and get there after a little trial and error. I think one of the things that has tripped me up is that it appears that, maybe, fieldbackground for TEntry just does not work on Windows. At least I haven't been able to get it to do so. – Watusimoto Nov 27 '21 at 02:34
  • I just tried a very simple example, and was able to get fieldbackground working with TEntry widgets, so something else is going on. I can no longer edit my comment to remove that complaint. – Watusimoto Nov 27 '21 at 02:41
  • 1
    Ah... it works on most themes, but not "vista". Blargh. – Watusimoto Nov 27 '21 at 02:53