From Apple to Raspberry Pi: A Gentle Introduction to Themed Widgets With ttk

Up to this point we have used tkinter widgets. For every widget, we had to set all the attributes. We could have this on off panel of three buttons and a label:

#TTK first example
#traditional tkinter for basis

from tkinter import *
#from tkinter import ttk

#make the window
root=Tk()
root.title('TTK Power Panel #1')

#make the frame

frame = Frame(root)
frame.grid(row=0, column=0)
#variables
status =StringVar()

#Styles

#controller
def onButtonPressed():
    status.set('On')
def offButtonPressed():
    status.set('Off')

#view

#label
status.set('System Off')
status_label = Label(frame, textvariable = status)
status_label.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')
status_label.grid(row=0,column=0,columnspan=3,sticky=EW)
#on Button
on_button = Button(frame, command = onButtonPressed, text = 'On')

on_button.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')
on_button.grid(row = 2, column = 0)

#off Button
off_button = Button(frame, command = offButtonPressed, text = 'Off')

off_button.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')
off_button.grid(row = 2, column = 1)

quit_button = Button(frame, command = quit, text = 'Quit')

quit_button.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')
quit_button.grid(row = 2, column = 2)

#main loop

mainloop()

Type it in, save and run.

Screenshot 2014-05-06 09.54.51

Each button uses the same .configure() for every widget:

.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')

While we have only three buttons, this can get tedious when there are many buttons. The application would be simpler to code and more consistent in its styling if there was a way to code for all of these. Later versions of tkinter does has such a feature. Tkinter introduced ttk-themed widgets to create one set of styles for all the widgets, or for certain types of widgets.

To use this, we need to import a special part of tkinter called ttk.

Change the from..import to this:

from tkinter import *
from tkinter import ttk

Change the on_button to this:

on_button = ttk.Button(frame, command = onButtonPressed, text = 'On')

Change the off_button to this:

off_button = ttk.Button(frame, command = offButtonPressed, text = 'Off')

Change the quit_button to this:

quit_button = Button(frame, command = quit, text = 'Quit')

Save and run. You will get syntax errors.

_tkinter.TclError: unknown option "-font"

The font option suddenly is no longer recognized. The ttk-themed widgets do not directly use font, foreground or background. They are all moved to a style sheet.

Comment out the three .configure() lines for the buttons:

#on_button.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')
#off_button.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')
#quit_button.configure(font=('Sans','14','bold'),background = 'blue', foreground = '#eeeeff')

Add the following just below the #Styles comment:

s = ttk.Style()
s.configure('TButton',background = 'blue', foreground = '#ddddff', font = ('Sans','14','bold'), relief = FLAT)

Run this and you will get all three buttons looking the same.

Screenshot 2014-05-06 09.56.19

The first parameter is the type of widget, confusingly called a widget class. It is not a Python class, but a type of widget. Most of the widget classes prefix a capital T to the name of the widget. The rest of the parameters is the attributes, just like we configured them with a .configure() for non-themed widgets.

Try placing the mouse pointer over a button, and we have a problem.

Screenshot 2014-05-06 09.56.30

The button highlights, and the text is unreadable. In our earlier lessons, we would use activebackground, and activeforeground to control this. However in ttk themed widgets, those do not exist. Instead a series of states can exist for the widget. One such state is active

For each state, we map an attribute different from the default set in .configure(). To do this use the .map() method. To change the text color to black we can do this:

s.map('TButton',foreground = [('active','black')] )

Add this to your code under the s.configure() line. While configure took straight assignments for the attributes, .map() is a bit more complicated. Each attribute takes a list, denoted by the square brackets.  The list has tuples of two strings with the form (state,attribute). Run this code.

Screenshot 2014-05-06 09.57.14

The button changes the text color when we hover over it. We can do the same for the background color. Add below the last .map() method the following:

s.map('TButton', background = [('active','#aaaaff')])

Save and run.

 

Screenshot 2014-05-06 09.57.58

When the mouse hovers or the button changes background color. This is the very basic use of the ttk themed widgets, but enough to get started. We’ll look at bit more into them in further lessons.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s