ttk.Combobox glitch when state is read-only and out of focus
Asked Answered
L

2

7

When a ttk.Combobox is read-only and not in focus, its text background gets white which differs from the gray field background and makes the combobox look ugly:

Example

The desired style would be the second one's. How to make a combobox work like that?

Lempres answered 4/9, 2013 at 9:46 Comment(0)
L
9

The solution is to change the ttk style like this:

s = ttk.Style()
s.map("TCombobox",
    selectbackground=[
        ('!readonly', '!focus', 'SystemWindow'),
        ('readonly', '!focus', 'SystemButtonFace'),
        ],
    )

This changes the behavior of the comboboxes globally. In the following demo (from which the screenshot of the question was made) I defined a custom style for the nicely working combobox as "Alt.TCombobox" and used that one for it:

# cboxdemo.py by Adam Szieberth (2013)
# Python 3.3.0

"""Read-only Ttk.Combobox style demo module.

The style of the second combobox has been slightly modified to
make text background match with combobox background when out of
focus.

In read-only state (which is default) you can notice that text
background gets white in the first (original styled) combobox
when focus moves towards. Second combobox looks nice then.

With the button you can test that the two works exactly the same
in writeable state.
"""

from random import randint
from tkinter import Button, Frame, StringVar, Tk
from tkinter.ttk import Combobox, Style

class App(Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.state = None
        self.style = Style()
        self.style.map("Alt.TCombobox",
            selectbackground=[
                ('!readonly', '!focus', 'SystemWindow'),
                ('readonly', '!focus', 'SystemButtonFace'),
                ],
            )
        self.button = Button(self, text="Change state!",
            command=self.switch)
        self.cbox1var, self.cbox2var = StringVar(), StringVar()
        self.cbox1 = Combobox(self,
            exportselection=0,
            values=["sex", "sleep", "eat", "drink", "dream",],
            textvariable=self.cbox1var,
            )
        self.cbox1.bind('<<ComboboxSelected>>', self.bfocus)
        self.cbox1.current(1)
        self.cbox2 = Combobox(self,
            exportselection=0,
            values=["fear", "clarity", "power", "old age",],
            style="Alt.TCombobox",
            textvariable=self.cbox2var,
            )
        self.cbox2.bind('<<ComboboxSelected>>', self.bfocus)
        self.cbox2.current(3)
        self.cbox1.pack()
        self.cbox2.pack()
        self.button.pack()
        self.switch()

    def bfocus(self, *args):
        if randint(0,1):
            self.button.focus()
            print('Focus moved!')
        else:
            print('Focus stayed.')

    def switch(self):
        if self.state == ['readonly']:
            self.state = ['!readonly']
            print('State is writeable!')
        else:
            self.state = ['readonly']
            print('State is read-only!')
        self.cbox1.state(self.state)
        self.cbox2.state(self.state)

if __name__ == "__main__":
    root = Tk()
    root.title('ttk.Combobox styling')
    App(root).pack()
    root.mainloop()
Lempres answered 4/9, 2013 at 9:46 Comment(0)
J
1

Another way to do it may be the following:

from tkinter.ttk import Combobox, Style

style = Style()
style.theme_create('custom_style',
                   parent='default',
                   settings={'TCombobox':
                             {'configure':
                              {'selectforeground': 'black',
                               'selectbackground': 'white'}
                              }
                             }
                   )
style.theme_use('custom_style')

Now you create a simple Combobox.

cb = Combobox(frame1, state='readonly')
cb['values'] = [
    'Please select',
    'Option 1',
    'Option 2',
    'Option 3'
]
cb.current(0)
cb.bind('<<ComboboxSelected>>', my_function_to_exec)
cb.grid(row=0, column=0, sticky='w')

This will not keep the text selected. Having done it as a "Theme" this will apply to all comboboxes.

Jaw answered 15/1, 2020 at 16:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.