ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: Python Programming on Win32

Python Programming on Win32 using Tkinter

Related Reading

Python Programming On Win32
Help for Windows Programmers
By Mark Hammond, Andy Robinson

by Mark Hammond

An excerpt from Chapter 20: GUI Development, from Python Programming on Win32. This is the first of three excerpts covering Tkinter, PythonWin, and wxPython. This excerpt only covers Tkinter.

In this chapter, we examine the various options for developing graphical user interfaces (GUIs) in Python.

We will look in some detail at three of the GUI toolkits that operate on the Windows platform: Tkinter, PythonWin, and wxPython. Each of these GUI toolkits provide a huge range of facilities for creating user interfaces, and to completely cover any of these toolkits is beyond the scope of this single chapter. Each framework would need its own book to do it justice.

Our intent in this chapter is to give you a feel for each of these GUI frameworks, so you can understand the basic model they use and the problems they were designed to address. We take a brief tour of each of these toolkits, describing their particular model and providing sample code along the way. Armed with this information, you can make an informed decision about which toolkit to use in which situation, have a basic understanding of how your application will look, and where it will run when finished.

The authors need to express their gratitude to Gary Herron for the Tkinter section, and Robin Dunn for the wxPython section. Their information helped us complete this chapter.

Tkinter

Tkinter is the Python interface to the Tk GUI toolkit current maintained by Scriptics (http://www.scriptics.com). Tkinter has become the de facto standard GUI toolkit for Python due mainly to its cross-platform capabilities; it presents a powerful and adaptable GUI model across the major Python platforms, including Windows 95/98/NT, the Macintosh, and most Unix implementations and Linux distributions.

This section gives a short description of the capabilities of Tkinter, and provides a whirlwind tour of the more important aspects of the Tkinter framework. To effectively use Tkinter, you need a more thorough description than is provided for here. Fredrik Lundh has made an excellent introduction to Tkinter programming available at http://www.pythonware.com/library.htm, and at time of printing a Tkinter book by Fredrik has just been announced, so may be available by the time you read this. For more advanced uses of Tkinter, you may need to refer directly to the Tk reference manual, available from the Scriptics site.

Two Python applications, tkBrowser and tkDemo, accompany this section. TkBrowser is a Doubletalk application, providing several views and some small editing capabilities of Doubletalk BookSets; TkDemo demonstrates a simple use of the core Tk user interface elements. Both applications are too large to include in their entirety, so where relevant, we include snippets.

Terminology

There's some new terminology with Tkinter, defined here for clarity:

Tk
A GUI toolkit provided as a library of C routines. This library manages and manipulates the windows and handles the GUI events and user interaction.

Tkinter
The Python Tk interface. A Python module that provides a collection of Python classes and methods for accessing the Tk toolkit from within Python.

Tcl
The (mostly hidden) language used by Tk and, hence, used by Tkinter to communicate with the Tk toolkit.

Widget
A user interface element, such as a text box, combo box, or top-level window. On Windows, the common terminology is control or window.

Pros and Cons of Tkinter

Before we launch into Tkinter programming, a brief discussion of the pros and cons of Tkinter will help you decide if Tkinter may be the correct GUI toolkit for your application. The following are often given as advantages of Tkinter:

Brevity
Python programs using Tkinter can be very brief, partly because of the power of Python, but also due to Tk. In particular, reasonable default values are defined for many options used in creating a widget, and packing it (i.e., placing and displaying).

Cross platform
Tk provides widgets on Windows, Macs, and most Unix implementations with very little platform-specific dependence. Some newer GUI frameworks are achieving a degree of platform independence, but it will be some time before they match Tk's in this respect.

Maturity
First released in 1990, the core is well developed and stable.

Extensibility
Many extensions of Tk exist, and more are being frequently distributed on the Web. Any extension is immediately accessible from Tkinter, if not through an extension to Tkinter, than at least through Tkinter's access to the Tcl language.

To balance things, here's a list of what's often mention as weaknesses in Tkinter:

Speed
There is some concern with the speed of Tkinter. Most calls to Tkinter are formatted as a Tcl command (a string) and interpreted by Tcl from where the actual Tk calls are made. This theoretical slowdown caused by the successive execution of two interpreted languages is rarely seen in practice and most real-world applications spend little time communicating between the various levels of Python, Tcl, and Tk.

Tcl
Python purists often balk at the need to install another (and to some, a rival) scripting language in order to perform GUI tasks. Consequently, there is periodic interest in removing the need for Tcl by using Tk's C-language API directly, although no such attempt has ever succeeded.

Tk lacks modern widgets
It's acknowledged that Tk presents a small basic set of widgets and lacks a collection of modern fancy widgets. For instance, Tk lacks paned windows, tabbed windows, progress meter widgets, and tree hierarchy widgets. However, the power and flexibility of Tk is such that you can easily construct new widgets from a collection of basic widgets. This fits in especially well with the object-oriented nature of Python.

Native look and feel
One common source of complaints is that Tkinter applications on Windows don't look like native Windows applications. As we shall see, the current version of Tkinter provides an interface that should be acceptable to almost everyone except the Microsoft marketing department, and we can expect later versions of Tkinter to be virtually indistinguishable.

Although many individuals could (and no doubt will) argue with some individual points on this list, it tends to reflects the general consensus amongst the Python community. Use this only as a guide to assist you in your decision-making process.

 

Running GUI Applications

Tkinter applications are normal Python scripts, but there are a couple of complications worth knowing about when running graphical applications under Windows. These are discussed in Chapter 3, of Python on Windows, but are important enough to reiterate here; what we say in this section applies equally to wxPython later in this chapter.

The standard Python.exe that comes with Python is known as a console application (this means it has been built to interact with a Windows console, otherwise known as a DOS box or command prompt). Although you can execute your Tkinter programs using Python.exe, your program will always be associated with a Windows console. It works just fine, but has the following side effects:

To get around this problem, Python comes with a special GUI version called Pythonw.exe. This is almost identical to the standard Python.exe, except it's not a console program, so doesn't suffer the problems described previously.

There are two drawbacks to this approach. The first is that .py files are automatically associated with Python.exe. As we saw in Chapter 3, this makes it simple to execute Python programs, but does present a problem when you want to use Pythonw.exe. To solve this problem, Python automatically associates the .pyw extension with Pythonw.exe ; thus, you can give GUI Python applications a .pyw extension, and automatically execute them from Windows Explorer, the command prompt, and so forth.

The second drawback is that because Pythonw.exe has no console, any tracebacks printed by Python aren't typically seen. Although Python prints the traceback normally, the lack of a console means it has nowhere useful to go. To get around this problem, you may like to develop your application using Python.exe (where the console is an advantage for debugging) but run the final version using Pythonw.exe.

"Hello World"

The easiest way to get a feel for Tkinter is with the ever popular "Hello World!" example. The result of this little program is shown in Figure 20-1.

from sys import exit
from Tkinter import *
root = Tk() 
Button(root, text='Hello World!', command=exit).pack() 
root.mainloop()
Figure 20-1. Tkinter's "Hello World"

 

As you can see, apart from the import statements, there are only three lines of interest. The root variable is set to the default top-level window automatically created by Tk, although applications with advanced requirements can customize the top-level frames. The code then creates a Tkinter button object, specifying the parent (the root variable), the text for the button, and the command to execute when clicked. We discuss the pack() method later in this section. Finally, turn control over to the main event-processing loop, which creates the Windows on the screen and dispatches user-interface events.

The other end of the World

From the extreme simplicity of the "Hello World" example, the other end of the scale could be considered the tkDemo sample included with this chapter. Although space considerations prevent us from examining this sample in detail, Figure 20-2 should give you an indication of the capabilities offered by Tkinter.

Figure 20-2. tkDemo example in action

 

 

Widgets

Core widgets

Tkinter implements a fairly small set of core widgets, from which other widgets or complete applications can be based. Table 20-1 lists these core widgets with a short description of how they are used.

Table 20-1: Core Tkinter Widgets

Widget Name

Description

Toplevel

Toplevel widgets are special in that they have no master widget and don't support any of the geometry-management methods (as discussed later). All other widgets are directly or indirectly associated with a Toplevel widget.

Frame

Used as a container widget for other child widgets. For instance, the tkDemo example consists of a number of frames within frames within frames to achieve its particular layout.

Label

Displays text or images.

Message

Displays text with automatic line-break and justification capabilities.

Text

Displays text with advanced formatting, editing, and highly interactive capabilities.

Canvas

Displays graphical items from a display list, with highly interactive capabilities.

Button
Checkbox
Entry
Scale
Radiobutton
List box
Scrollbar

Standard simple entry widgets, also known as the control widgets.

Menu
Menubutton

Widgets for implementing and responding to menus.

Quite a few of these widgets are demonstrated in the tkBrowser sample, and every one gets an exercise in the tkDemo sample, so you are encouraged to experiment with these samples to get a feel for the capabilities of each widget. Of these widgets, we will discuss two of the most popular and powerful in more detail: the Text and Canvas widgets.

The Text widget provides for the display and editing of text, as you would expect from a text control. The Text widget is also capable of supporting embedded images and child windows, but the real power of the text control can be found in its support of indexes, tags, and marks:

Indexes
Indexes provide a rich model for describing positions in the text control. The position specification can be in terms of line and column position (relative or absolute), pixel position, special system index names, and so forth.

Tags
Tags are an association between a name and one or more regions of text. There is no restriction on overlapping regions, so a character may belong to any number of tags, and tags can be created and destroyed dynamically. In addition, the text associated with a tag may be given any number of display characteristics (such as font, color specifications, and so forth). When we combine these capabilities with the Tkinter event model described later, it becomes easy to build highly interactive applications (such as a web browser) around this Text widget.

Marks
A mark is a single position within the text (or more accurately, a position between two characters). Marks flow naturally with the surrounding text as characters are inserted and deleted, making them particularly suitable for implementing concepts such as bookmarks or breakpoints. Tkinter manages a number of predefined marks, such as insert, which defines the current insertion point.

The Canvas widget displays graphical items, such as lines, arcs, bitmaps, images, ovals, polygons, rectangles, text strings, or arbitrary Tkinter widgets. Like the Text widget, the Canvas widget implements a powerful tagging system, allowing you to associate any items on the canvas with a name.

Dialog and other noncore widgets

Many useful widgets are actually built from the core widgets. The most common example is the dialog widget, and recent versions of Tkinter provide some new sophisticated dialog widgets similar to the Windows common dialogs. In many cases when running on Windows, the standard Windows dialog is used.

Many of these dialogs come in their own module. Table 20-2 lists the common dialog box modules and their functionality.

Table 20-2: Tkinter Common Dialog Box Modules

Module Name

Description

tkMessageBox

Simple message box related dialogs, such as Yes/No, Abort/Retry/Ignore, and so forth.

tkSimpleDialog

Contains base classes for building your own dialogs, and also includes a selection of simple input dialogs, such as asking for a string, integer, or float value.

tkFileDialog

A dialog with functionality very close to the Windows common file dialogs.

tkColorChooser

A dialog for choosing a color.

There are many other widgets available; both included with the Tkinter package, and also available externally. One interesting and popular source of Tkinter widgets can be found in the Python megawidgets (Pmw) package. This package comes with excellent documentation and sample code and can be found at http://www.dscpl.com.au/pmw/.

In most cases, you build your own dialogs by deriving them from the tkSimpleDialog.Dialog. Our tkBrowser sample defines an EditTransaction class that shows an example of this.

Widget properties and methods

Tkinter provides a flexible and powerful attribute set for all widgets. Almost all attributes can be set at either widget-creation time or once the widget has been created and displayed. Although Tkinter provides obvious attributes for items such as the color, font, or visible state of a widget, the set of enhanced attributes for widgets is usually the key to tapping the full potential of Tkinter.

Tkinter makes heavy use of Python keyword arguments when specifying widget attributes. A widget of any type (for instance a Label) is constructed with code similar to:

w = Label(master, option1=value1, option2=value2,...)

And once constructed, can be reconfigured at any time with code like:

w.configure(option1=value1, option2=value2, ...)

For a specific example, you can create a label with the following code:

label = Label(parent, background='white', 
                      text='Hello World!',
                      relief=RAISED, 
                      borderwidth=3)

And provide an annoying blinking effect by periodic execution of:

label.configure(background='red')

And:

label.configure(background='white')

There are dozens of options that can be specified for each widget. Table 20-3 lists a few common properties available for each widget.

Table 20-3: Common Tkinter Widget Properties

Property

Description

height
width

The height and width of the widget in pixels.

background
foreground

The color of the widget as a string. You can specify a color by name (for example, red or light blue), or you can specify each of the RGB components in hexadecimal notation prefixed with a # (e.g., #ffffff for white).

relief

A 3D appearance for the object (RAISED, SUNKEN, RIDGE, or GROOVE) or a 2D appearance (FLAT or SOLID).

borderwidth

Width of the border, in pixels.

text wrap
justify

The Window text (i.e., the caption) for the widget and additional formatting options for multiline widgets.

font

The font that displays the text. This can be in a bewildering array of formats: some platform-independent and some platform-dependent. The most common form is a tuple containing font name, point size, and style (for example, ("Times", 10, "bold"). Tkinter guarantees that the fonts Times, Helvetica, and Courier exist on all platforms, and styles can be any combination of bold, roman, italic, underline, and overstrike, which are always available, with Tkinter substituting the closest matching font if necessary.

command
variable

Techniques used by control widgets to communicate back to the application. The command option allows you to specify an arbitrary Python function (or any callable Python object) to be invoked when the specified action occurs (e.g., when a Button widget is pushed). Alternatively, several widgets take the variable option and, if specified, must be an instance of one of the StringVar, IntVar, DoubleVar, or BooleanVar classes (or subclass). Once set up, changes to the widget are immediately reflected in the object, and changes in the object are immediately reflected to the widget. This is demonstrated in tkBrowser.py in a number of places including the EditTransaction class, which uses this technique for managing the data shown in the dialog.

There are also dozens of methods available for each widget class, and the Tkinter documentation describes these in detail, but there is one important method we mention here because it's central to the Tkinter event model.

The bind() method is simple, but provides an incredible amount of power by allowing you to bind a GUI event to a Python function. It takes two parameters, the event you wish to bind to (specified as a string) and a Python object to be called when the event fires.

The power behind this method comes from the specification of the event. Tkinter provides a rich set of events, ranging from keyboard and mouse actions to Window focus or state changes. The specification of the event is quite intuitive (for example, <Key> binds any key, <Ctrl-Alt-Key-Z> is a very specific key, <Button-1> is a the first mouse-button click, and so forth) and covers over 20 basic event types. You should consult the Tkinter reference guides for a complete set of events supported by Windows and a full description of the Tkinter event model.

Geometry Management

Tkinter provides a powerful concept typically not found in Windows GUI toolkits, and that is geometry management. Geometry management is the technique used to lay out child widgets in their parent (for example, controls in a dialog box). Most traditional Windows environments force you to specify the absolute position of each control. Although this is specified in dialog units rather than pixels and controls can be moved once created, Tkinter provides a far more powerful and flexible model.

Tkinter widgets provide three methods for geometry management, pack(), grid(), or place().

place() is the simplest mechanism and similar to what most Windows users are used to; each widget has its position explicitly specified, either in absolute or relative coordinates. The grid() mechanism, as you may expect, automatically aligns the widgets in a grid pattern, while the pack() method is the most powerful and the most commonly used. When widgets are packed, they are automatically positioned based on the size of the parent and the other widgets already placed. All of these techniques allow customization of the layout process, such as the padding between widgets.

These geometry-management capabilities allow you to define user interfaces that aren't tied to particular screen resolutions and can automatically resize and layout controls as the window size changes, capabilities that most experienced Windows user-interface programmers will know are otherwise difficult to achieve. Our two samples (described next) both make extensive use of the pack() method, while the tkDemo sample also makes limited use of grid().

Tkinter Sample Code

We have included a sample Doubletalk browser written in Tkinter. This is a fully functional transaction viewer and editor application and is implemented in tkBrowser.py. This implements a number of features that demonstrate how to build powerful applications in Tkinter. A number of dialogs are presented, including the transaction list, and the detail for each specific transaction. To show how simple basic drawing and charting is, a graphical view of each account is also provided. Rather than labor over the details of this sample, the best thing to do is just to run it. Then once you have a feel for the functionality, peruse the source code to see the implementation. There are ample comments and documentation strings included less than 700 lines of source. Figure 20-4 shows our final application in action.

Figure 20-4. The Tkinter Doubletalk browser in action

 

The second sample is TkDemo.py, which is a demonstration of all the Tkinter core widgets. It is highly animated and provides a good feel for the basic operation of these widgets.

As mentioned previously, Tkinter is the standard GUI for Python applications, therefore you can find a large number of resources both in the standard Python documentation and referenced via the Python web site.

Tkinter Conclusion

Tkinter is excellent for small, quick GUI applications, and since it runs on more platforms than any other Python GUI toolkit, it is a good choice where portability is the prime concern.

Obviously we haven't been able to give Tkinter the depth of discussion it warrants, but it's fair to say that almost anything that can be done using the C language and Tk can be done using Python and Tkinter. One example is the Python megawidgets (PMW) package mentioned previously; this is a pure Python package that creates an excellent widget set by building on the core Tkinter widgets.

To learn more about any of the Tkinter topics discussed here, you may like to refer to the following sources:

Mark Hammond is an independent Microsoft Windows consultant working out of Melbourne, Australia.

Andy Robinson is a London-based consultant specializing in business analysis, object-oriented design, and Windows development.


Discuss this article in the O'Reilly Network Python Forum.

Return to the Python DevCenter.

Copyright © 2009 O'Reilly Media, Inc.