Book Image

Tkinter GUI Application Development Blueprints - Second Edition

By : Bhaskar Chaudhary
Book Image

Tkinter GUI Application Development Blueprints - Second Edition

By: Bhaskar Chaudhary

Overview of this book

Tkinter is the built-in GUI package that comes with standard Python distributions. It is a cross-platform package, which means you build once and deploy everywhere. It is simple to use and intuitive in nature, making it suitable for programmers and non-programmers alike. This book will help you master the art of GUI programming. It delivers the bigger picture of GUI programming by building real-world, productive, and fun applications such as a text editor, drum machine, game of chess, audio player, drawing application, piano tutor, chat application, screen saver, port scanner, and much more. In every project, you will build on the skills acquired in the previous project and gain more expertise. You will learn to write multithreaded programs, network programs, database-driven programs, asyncio based programming and more. You will also get to know the modern best practices involved in writing GUI apps. With its rich source of sample code, you can build upon the knowledge gained with this book and use it in your own projects in the discipline of your choice.
Table of Contents (12 chapters)

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 to styling features that are available in Tkinter is supplied in the following section.

You may recall that we can specify widget options at the time of its instantiation, as follows:

my_button = tk.Button(parent, **configuration options)

Alternatively, you can specify the widget options by using configure() in the following way:

my_button.configure(**options)

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(r), green(g), and blue(b). 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 as font="{nimbus roman} 36 bold italic".
  • fontsize: This is in the printer's point unit (pt) or pixel unit (px).
  • fontstyle: This is a mix of normal/bold/italic and underline/overstrike.

The following are 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 for 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 just a text file where you can specify 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:

import tkinter as tk
root = tk.Tk()
root.configure(background='#4D4D4D')#top level styling
# connecting to the external styling optionDB.txt
root.option_readfile('optionDB.txt')
#widget specific styling
mytext = tk.Text(root, background='#101010', foreground="#D6D6D6",
borderwidth=18, relief='sunken',width=17, height=5)
mytext.insert(tk.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 get their styling from optionDB.txt file
tk.Button(root, text='*').grid(row=1, column=1)
tk.Button(root, text='^').grid(row=1, column=2)
tk.Button(root, text='#').grid(row=1, column=3)
tk.Button(root, text='<').grid(row=2, column=1)
tk.Button(root, text='OK', cursor='target').grid(row=2, column=2)#changing cursor style
tk.Button(root, text='>').grid(row=2, column=3)
tk.Button(root, text='+').grid(row=3, column=1)
tk.Button(root, text='v').grid(row=3, column=2)
tk.Button(root, text='-').grid(row=3, column=3)
for i in range(9):
tk.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:

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.