States and Themes#

../_images/03themes_states.jpg

Script 03states_themes.py#

Show/Hide Code 03states_themes.py

"""
Ttk Theme Selector and State.

Although it is a theme selector, you won't notice many changes since
there are only radiobuttons, a frame around and the selected widget.

The state selector only applies to the selected widget.

"""
from tkinter import StringVar, Tk
from tkinter.ttk import Frame, Style, Button, Radiobutton, Label

class App:
    def __init__(self,root):
        self.fr = Frame(root)
        self.fr.pack(fill='both', expand=1)
        ## uncomment following 5 lines if using ttkthemes
        '''
        try:  
            import ttkthemes as ts 
            self.style = ts.themed_style.ThemedStyle()
        except (NameError, AttributeError):
            self.style = Style()
        '''
        self.style = Style() ## comment out if using ttkthemes
        self._setup_widgets()

    def _change_theme(self):
        newtheme = self.theme_val.get()
        self.style.theme_use(newtheme)

    def _change_state(self):
        oldstate = self.but.state()
        if len(oldstate) > 0:
            # convert tuple to string 
            oldst = " ".join(str(x) for x in oldstate) 
            self.but.state(['!'+oldst])
        newstate = self.state_val.get()
        self.but.state([newstate])

    def _setup_widgets(self):
        l = Label(self.fr, text="Dont't forget click and hover, \n \
or see more by using the radio buttons")
        l.grid(column=0,row=0,columnspan=3,padx=5,pady=2, sticky='n')
        themes = sorted(list(self.style.theme_names()))
        # Create rasio buttons which will display themes
        self.theme_val = StringVar()
        for ix, val in enumerate(themes):
            themes_rb = Radiobutton(self.fr, value=val, text=val,
                 variable=self.theme_val, command=self._change_theme)
            themes_rb.grid(column=0,row=ix+1,padx=5,pady=2, sticky='nw')

        states = ['active', 'alternate', 'background', 'disabled',
                      'focus', 'invalid', 'pressed', 'readonly', 'selected']
        # Create rasio buttons which will display widget states
        self.state_val = StringVar()
        for iy, state in enumerate(states):
            st_rb = Radiobutton(self.fr, value=state, text=state,
                   variable=self.state_val, command=self._change_state)
            st_rb.grid(column=1,row=iy+1,padx=5,pady=5, sticky='nw')

        # selected widget, if using scrollbar place in own frame
        self.but = Button(self.fr, text='Button State')
        self.but.grid(column=3,row=ix+2,padx=5,pady=5)

if __name__ == "__main__":
    Root = Tk()
    Root.title("Ttk Theme and State Selector")
    app = App(Root)
    Root.mainloop()

there is no problem changing themes, however when changing states we need to cancel the previous state by applying the opposite state (you remember the state prefixed with an exclamion mark), we also have to ensure that we are dealing with a string rather than a tuple, further we must ensure that the tuple is not empty. In our example we are changing the state of a button, you can modify this or add another widget as required.

As we have already seen states are not only used singly, they may be used in combination, particularly in dynamic situations. The common themes do not always use the same states for any particular widget, if we are building custom widgets keep this in mind, as ever test using different themes. Check out the table 03mapped_states.csv to see the states that the themes use with which widget.

Show/Hide Table 03mapped_states.csv
03mapped_states.csv#

Widget

Class Name

mapped states alt

mapped states clam

mapped states classic

mapped states default

Common

.

disabled, active

disabled, active, focus

disabled, active, focus disabled, active

Button

TButton

{pressed !disabled}, {active !disabled}, alternate

disabled, pressed, active, alternate {!disabled pressed}

{!disabled pressed}

Checkbutton

TCheckbutton

disabled, pressed

disabled, pressed

pressed, selected

pressed, selected

Combobox

TCombobox

readonly, disabled

active, pressed, {readonly focus}

readonly, disabled

readonly, disabled

Entry

TEntry

readonly, disabled

readonly, focus

readonly, disabled

readonly, disabled

Notebook

TNotebook.Tab

selected

selected

selected

selected

Radiobutton

TRadiobutton

disabled, pressed

disabled, pressed

pressed, selected

pressed, selected

Scale

TScale

{pressed !disabled}

Scrollbar

TScrollbar

{pressed !disabled}

disabled

Spinbox

TSpinbox

readonly, disabled

readonly, disabled

readonly, disabled

readonly, disabled

Treeview

Treeview

selected

selected

selected

selected