Doing it in style
So far, we have relied on Tkinter to provide specific platform-based styling for our widgets. However, you can specify your own styling of widgets, such as their color, font size, border width, and relief. A brief introduction of styling features that are available in Tkinter is covered in the following section.
You may recall that we can specify the widget options at the time of its instantiation, as follows:
my_button = Button(parent, **configuration options)
Alternatively, you can specify the widget options by using configure ()
in the following way:
my_button.configure(**options)
The styling options are also specified as options to the widgets either at the time of creating the widgets, or later by using the configure
option.
Specifying styles
Under the purview of styling, we will cover how to apply different colors, fonts, border widths, reliefs, cursors, and bitmap icons to widgets.
First, let's see how to specify the color options for a widget. You can specify the following two types of color for most widgets:
- The background color
- The foreground color
You can specify the color by using hexadecimal color codes for the proportion of red, green, and blue. The commonly used representations are #rgb
(4 bits), #rrggbb
(8 bits), and #rrrgggbbb
(12 bits).
For example, #fff
is white, #000000
is black, #f00
is red (R=0xf
, G=0x0
, B=0x0
), #00ff00
is green (R=0x00
, G=0xff
, B=0x00
), and #000000fff
is blue (R=0x000
, G=0x000
, B=0xfff
).
Alternatively, Tkinter provides mapping for standard color names. For a list of predefined named colors, visit http://wiki.tcl.tk/37701 or http://wiki.tcl.tk/16166.
Next, let's have a look at how to specify fonts for our widgets. A font can be represented as a string by using the following string signature:
{font family} fontsize fontstyle
The elements of the preceding syntax can be explained as follows:
font family
: This is the complete font family long name. It should preferably be in lowercase, such asfont="{nimbus roman} 36 bold italic"
.fontsize
: This is in a printer's point unit (pt) or pixel unit (px).fontstyle
: This is a mix ofnormal
/bold
/italic
andunderline
/overstrike
.
The following are the examples that illustrate the method of specifying fonts:
widget.configure (font='Times 8') widget.configure(font='Helvetica 24 bold italic')
If you set a Tkinter dimension in a plain integer, the measurements take place in pixel units. Alternatively, Tkinter accepts four other measurement units, which are m (millimeters), c (centimeters), i (inches), and p (printer's points, which are about 1/72").
For instance, if you want to specify the wrap length of a button in terms of a printer's point, you can specify it as follows:
button.configure(wraplength="36p")
The default border width for most Tkinter widgets is 2 px
. You can change the border width of the widgets by specifying it explicitly, as shown in the following line:
button.configure(borderwidth=5)
The relief
style of a widget refers to the difference between the highest and lowest elevations in a widget. Tkinter offers six possible relief styles—flat
, raised
, sunken
, groove
, solid
, and ridge
:
button.configure(relief='raised')
Tkinter lets you change the style of the mouse cursor when you hover over a particular widget. This is done by using the option
cursor, as follows:
button.configure(cursor='cross')
For a complete list of available cursors, refer to https://www.tcl.tk/man/tcl8.6/TkCmd/cursors.htm.
Though you can specify the styling options at each widget level, sometimes it may be cumbersome to do so individually for each widget. Widget-specific styling has the following disadvantages:
- It mixes logic and presentation into one file, making the code bulky and difficult to manage
- Any change in styling has to be applied to each widget individually
- It violates the don't repeat yourself (DRY) principle of effective coding, as you keep specifying the same style for a large number of widgets
Fortunately, Tkinter now offers a way to separate presentation from logic and specify styles in what is called the external option database. This is nothing but a text file where you can specify the common styling options.
A typical option database text file looks like this:
*background: AntiqueWhite1 *Text*background: #454545 *Button*foreground: gray55 *Button*relief: raised *Button*width: 3
In its simplest use, the asterisk (*
) symbol here means that the particular style is applied to all the instances of the given widget. For a more complex usage of the asterisk in styling, refer to http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/resource-lines.html.
These entries are placed in an external text (.txt
) file. To apply this styling to a particular piece of code, you can simply call it by using the option_readfile()
call early in your code, as shown here:
root.option_readfile('optionDB.txt')
Let's have a look at an example (see code 1.12.py
) of using this external styling text file in a program:
from tkinter import * root = Tk() root.configure(background='#4D4D4D')#top level styling # connecting to the external styling optionDB.txt root.option_readfile('optionDB.txt') #widget specific styling mytext = Text(root, background='#101010', foreground="#D6D6D6", borderwidth=18, relief='sunken',width=17, height=5) mytext.insert(END, "Style is knowing who you are, what you want to say, and not giving a damn.") mytext.grid(row=0, column=0, columnspan=6, padx=5, pady=5) # all the below widgets derive their styling from optionDB.txt file Button(root, text='*').grid(row=1, column=1) Button(root, text='^').grid(row=1, column=2) Button(root, text='#').grid(row=1, column=3) Button(root, text='<').grid(row=2, column=1) Button(root, text='OK', cursor='target').grid(row=2, column=2)#changing cursor style Button(root, text='>').grid(row=2, column=3) Button(root, text='+').grid(row=3, column=1) Button(root, text='v').grid(row=3, column=2) Button(root, text='-').grid(row=3, column=3) for i in range(9): Button(root, text=str(i+1)).grid(row=4+i//3, column=1+i%3) root.mainloop()
The following is a description of the preceding code:
- The code connects to an external styling file called
optionDB.txt
that defines common styling for the widgets. - The next segment of code creates a Text widget and specifies styling on the widget level.
- The next segment of code has several buttons, all of which derive their styling from the centralized
optionDB.txt
file. One of the buttons also defines a custom cursor.
Specifying attributes such as font sizes, the border width, the widget width, the widget height, and padding in absolute numbers, as we have done in the preceding example, can cause some display variations between different operating systems such as Ubuntu, Windows, and Mac respectively, as shown in the following screenshot. This is due to differences in the rendering engines of different operating systems.
Tip
When deploying cross-platform, it is better to avoid specifying attribute sizes in absolute numbers. It is often the best choice to let the platform handle the attribute sizes.