Tkinter Summary

This is a quick reference for Tkinter. It is intended as a supplement to proper reference material, not as a replacement. The depth ranges from the simple to the arcane. I tend to add new topics as I find myself having difficulty locating information I need.

Basic Tk Application

import Tkinter
	root = Tkinter.Tk()
	# set up your interface, then run it with:
	root.mainloop()

Standard Widgets

Basic Widgets: Toplevel, Frame, Button, Checkbutton, Entry, Label, Listbox, OptionMenu, Photoimage, Radiobutton, Scale.

Fancy Widgets: Canvas, Text. These have taggable contents that act like objects.

Hard to Use: Menu, Menubutton, Scrollbar.

Tk Variables: StringVar, IntVar, DoubleVar, BooleanVar. These are data containers needed by certain widgets, are handy with many others for easy access to contents, and can trigger callbacks when their data is changed.

Extra Modules (not loaded by "import Tkinter")

tkFont defines the Font class for font metrics and getting names of fonts. If you set a widget's font to a Font object, then changing the Font live-updates the widget.

FileDialog defines FileDialog, LoadFileDialog, SaveFileDialog. Here is an example:

fdlg = FileDialog.LoadFileDialog(root, title="Choose A File")
	fname = fdlg.go() # opt args: dir_or_file=os.curdir, pattern="*", default="", key=None)
	if file == None: # user cancelled

tkColorChooser defines askcolor(initialcolor), which returns a user-chosen color.

tkSimpleDialog defines askinteger(title, prompt, initialvalue, minvalue, maxvalue), askfloat and askstring.

Examine the source code in .../Lib/lib-tk to find others and see examples of use.

Geometry Management

The Packer

pack(side="top/right/bottom/left", expand=0/1, anchor="n/nw/w...", fill="x/y/both")

The Gridder

grid(row, column, rowspan=?, columnspan=?, sticky="news", ipadx=?, ipady=?, padx=?, pady=?)

columnconfigure(row, weight=?, minsize=?, pad=?)

columnconfigure(column, weight=?, minsize=?, pad=?)

Events and Callbacks

Events

Events are described as a string: "<modifiers-type-qualifier>".

Event types include:

Warning: which widgets see which events varies by platform.

Qualifiers for KeyPress and KeyRelease are keysyms. Letters and numbers are used as is, but punctuation and all other keys require special case-sensitive names, including: comma, period, dollar, asciicircum, numbersign, exclam, Return, Escape, BackSpace, Tab, Up, Down, Left, Right... When in doubt, run an interactive test such as the example given below.

To trigger a callback when a widget sees an event, use bind:
widget.bind(event, callback)

Here is an example that displays the key symbol for any key pressed:

	#!/usr/local/bin/Python
	"""Displays the keysym for each KeyPress event as you type."""
	import Tkinter
	
	root = Tkinter.Tk()
	root.title("Keysym Logger")
	
	def reportEvent(event):
	print 'keysym=%s, keysym_num=%s' % (event.keysym, event.keysym_num)
	
	text  = Tkinter.Text(root, width=20, height=5, highlightthickness=2)
	
	text.bind('<KeyPress>', reportEvent)
	
	text.pack(expand=1, fill="both")
	text.focus_set()
	root.mainloop()

Protocol Handler WM_DELETE_WINDOW

A Destroy event callback is fired too late to clean up widgets or prevent window destruction. To do either of these, use the WM_DELETE_WINDOW protocol handler. (But if you are trying to clean up as your application exits, use the standard python library "atexit", instead; it's simpler!) This replaces the default behavior, so you must destroy the window yourself if you actually want it destroyed. The callback receives no arguments.

toplevel.protocol("WM_DELETE_WINDOW", callback)

There are two other protocols: WM_SAVE_YOURSELF and WM_TAKE_FOCUS. I'm not sure what use they are.

Widget Commands

Widgets such as Button support a "command" parameter. The callback receives no arguments. This is by far the best way to fire a callback when a Button is pressed because there is no single mouse event that does the same job. It is a pain that "command" callbacks send the callback function no data, but you can easily use a Callback Shim to rectify the situation.

Tracing Variables

To trigger a callback when a Tk variable is changed, use trace_variable:
traceName = tkvar.trace_variable(mode, callback)

After: Timed Events and Animation

To trigger a callback after a specified delay, e.g. for animation, use after:
widget.after(timems, callback, arg1, arg2...)

File/Socket Handlers

The question is how to communicate over a socket (especially how to read data) without tying up the event loop or being very inefficient. There are several options:

File handlers

A file handler will call a callback when a file or socket has data to read or write. File handlers are simple and well integrated into Tkinter. Unfortunately they do not work on Windows (at least as of Python 2.3.4 and Windows XP). But if your program only has to run on unix and/or MacOS X, they are worth considering because they are so easy to use.

wdg.tk.createfilehandler(file_or_socket, mask, callback)
where wdg is any Tkinter widget (if you don't have one handy, create a new frame for the purpose).

Tcl sockets

Tcl sockets are fully cross-platform, but a bit more difficult to use because they require some tcl code. Still, it's not very difficult and well worth the effort to get fuly cross-platform code. For an example of how to use tcl sockets, download my RO package and look at RO.Comm.TkSocket. See also this posting by Matthew Cincera that I used to get started (with thanks to Stephane Beland for the pointer).

Twisted Framework

Twisted Framework is a free cross-platform networking library that works with several different GUI toolkits (nor does it actually require a GUI toolkit). It has a very good reputation. I confess I have not yet used it myself, but expect to switch to it someday.

Callback Shims (Currying Functions)

I find I often wish to pass extra data to a callback function, in addition that that normally given. For instance the Button widget sends no arguments to its command callback, but I may want to use one callback function to handle multiple buttons, in which case I need to know which button was pressed.

The way to handle this is to define the callback function just before you pass it to the widget and include any extra information that you require. Unfortunately, like most languages, Python doesn't handle the mixing of early binding (information known when the function is defined) and late binding (informtation known when the function is called) particularly well. I personally find the easiest and cleanest solution is:

I hope the example given below makes this clearer.

The callback shim I use is RO.Alg.GenericCallback, which is available in my RO package. A simplified version that does not handle keyword arguments is given in the example below. All shim code is based on a python recipe by Scott David Daniels, who calls this "currying a function" (a term that is probably more common than "callback shim").

	#!/usr/local/bin/Python
	"""Example showing use of a callback shim"""
	import Tkinter
	
	def doButton(buttonName):
	"""My desired callback. I'll need a callback shim
	because Button command callbacks receive no arguments.
	"""
	print buttonName, "pressed"
	
	class SimpleCallback:
	"""Create a callback shim. Based on code by Scott David Daniels
	(which also handles keyword arguments).
	"""
	def __init__(self, callback, *firstArgs):
		self.__callback = callback
		self.__firstArgs = firstArgs
	
	def __call__(self, *args):
		return self.__callback (*(self.__firstArgs + args))
	
	root = Tkinter.Tk()
	
	buttonNames = ("Button 1", "Button 2", "Button 3")
	for name in buttonNames:
	callback = SimpleCallback(doButton, name)
	Tkinter.Button(root, text=name, command=callback).pack()
	
	root.mainloop()

Indexing

Text Widget

These may be modified by appending the following strings:

For example "1.0 lineend" referst to the end of first line.

Entry Widget

Getting Information from Widgets

There are several ways of retrieving configuration information from a widget:

In all cases, each setting is returned as a string. This can be a major headache. For instance boolean values will be "0" or "1" (both of which are logically true, in Python). The problem is even worse when trying to retrieve things that are normally Tkinter objects, such as Tk variables or wigets. The following example illustrates the problem (though in such a simple situation you already have the original Tk objects) and some of the solutions discussed below:

import Tkinter
root = Tkinter.Tk()
aVar = Tkinter.StringVar()
aLabel = Tkinter.Label(textvar = aVar)
aLabel["textvar"]
  'PY_VAR0'
root.setvar(aLabel["textvar"], "foo")
aLabel.getvar(aLabel["textvar"])
  'foo'
str(aLabel)
  '.8252000'
root.nametowidget(str(aLabel))
  <Tkinter.Label instance at 0x7dea60>
aLabel.master
  <Tkinter.Label instance at 0x7dea60>
root.master
  None
	

The solution depends on what you are retriving:

Hints

General hints:

Here are some common pitfalls in Tkinter and python, and how to avoid them:

Less common Tkinter pitfalls:

Resources

Written by Russell Owen. Last updated 2006-10-20 (revised the Hints section including a hint suggested by Troels Therkelsen and revised Resources). This document may be freely distributed but must not be sold.