So far, we've seen only the most elementary kind of event handling: the callbacks performed on callables installed with the command= option of buttons and menu entries of various kinds. Tkinter also lets you install callables to call back when needed to handle a variety of events. However, Tkinter does not let you create your own custom events; you are limited to working with events predefined by Tkinter itself.
General event callbacks must accept one argument event that is a Tkinter event object. Such an event object has several attributes describing the event:
A single-character string that is the key's code (only for keyboard events)
A string that is the key's symbolic name (only for keyboard events)
Button number (only for mouse-button events); 1 and up
Mouse position, in pixels, relative to the upper left corner of the widget
Mouse position, in pixels, relative to the upper left corner of the screen
The widget in which the event has occurred
To bind a callback to an event in a widget w, call w.bind, describing the event with a string, usually enclosed in angle brackets ('<...>'). The following example prints 'Hello World' each time the user presses the Enter key:
from Tkinter import * root = Tk( ) def greet(*ignore): print 'Hello World' root.bind('<Return>', greet) root.mainloop( )
Method tag_bind of classes Canvas and Text, covered earlier in this chapter, lets you bind event callbacks to specific sets of items of a Canvas instance, or to ranges within a Text instance.
Frequently used event names, which are almost all enclosed in angle brackets, fall into a few categories.
The user clicked any key. The event object's attribute char tells you which key, but for normal keys only, not for special keys. The event object's attribute keysym is equal to attribute char for letters and digits, is the character's name for punctuation characters, and is the key name for special keys, as covered in the next paragraph.
Special keys are associated with event names: F1, F2, ..., up to F12 for function keys; Left, Right, Up, Down for arrow keys; Prior, Next for page-up, page-down; BackSpace, Delete, End, Home, Insert, Print, Tab, for keys so labeled; Escape for the key often labeled Esc; Return for the key often labeled Enter; Caps_Lock, Num_Lock, Scroll_Lock for locking-request keys; Alt_L, Control_L, Shift_L for the modifier keys Alt, Ctrl, Shift (without distinction among the multiple instances of such modifier keys in a typical keyboard). All of these event names are placed within angle brackets, like almost all event names.
Normal keys are associated with event names without surrounding angle bracketsthe only event names to lack such brackets. The event name of each normal key is just the associated character, such as 'w', '1', or '+'. Two exceptions are the Space key, whose event name is '<space>', and the key associated with the less-than character, whose event name is '<less>'.
All key event names can be modified by prefixing 'Alt-', 'Shift-', or 'Control-'. In this case, the whole event name does always have to be surrounded with '<...>'. For example, '<Control-Q>' and '<Alt-Up>' name events corresponding to normal or special keys with modifiers.
The user pressed the left, middle, or right mouse-button. A two-button mouse produces only events Button-1 and Button-3, since it has no middle button.
The user moved the mouse while pressing the left, middle, or right mouse button (there is no mouse event for mouse motion without pressing a button, except for Enter and Leave).
The user released the left, middle, or right mouse button.
The user double-clicked the left, middle, or right mouse button (such an action also generates Button-1, Button-2, or Button-3 before the double-click event).
The user moved the mouse so that the mouse entered the widget.
The user moved the mouse so that the mouse exited the widget.
Each widget w supplies the following event-related methods.
bind |
w.bind(event_name,callable[,'+']) |
w.bind(event_name,callable) sets callable as the callback for event_name on w. w.bind(event_name,callable,'+') adds callable to the previous bindings for event_name on w.
bind_all |
w.bind_all(event_name,callable[,'+']) |
w.bind_all(event_name,callable) sets callable as the callback for event_name on any widget of the application, whatever widget w you call the method on. w.bind_all(event_name,callable,'+') adds callable to the previous bindings for event_name on any widget.
unbind |
w.unbind(event_name) |
Removes all callbacks for event_name on w.
unbind_all |
w.unbind_all(event_name) |
Removes all callbacks for event_name on any widget, previously set by calling method bind_all on any widget.
The following example shows how to detect key presses and mouse-button presses and releases using the bind_all method:
import Tkinter from Tkinter import * root = Tk( ) prompt='Click any button, or press a key' L = Label(root, text=prompt, width=len(prompt)) L.pack( ) def key(event): if event.char= =event.keysym: msg ='Normal Key %r' % event.char elif len(event.char)= =1: msg ='Punctuation Key %r (%r)' % (event.keysym, event.char) else: msg ='Special Key %r' % event.keysym L.config(text=msg) L.bind_all('<Key>', key) def do_mouse(eventname): def mouse_binding(event): msg = 'Mouse event %s' % eventname L.config(text=msg) L.bind_all('<%s>'%eventname, mouse_binding) for i in range(1,4): do_mouse('Button-%s'%i) do_mouse('ButtonRelease-%s'%i) do_mouse('Double-Button-%s'%i) root.mainloop( )
Each widget w supplies the following other callback-related methods.
after |
w.after(ms,callable,*args) |
Starts a timer that calls callable(*args) about ms milliseconds from now. Returns an ID that you can pass to after_cancel to cancel the timer. The timer is one-shot: for a function to be called periodically, the function itself must call after to install itself as a callback again.
after_cancel |
w.after_cancel(id) |
Cancels the timer identified by id.
after_idle |
w.after_idle(callable,*args) |
Registers a callback to callable(*args) to be performed when the event loop is idle (i.e., when all pending events have been processed).
The following example shows how to use after to implement a simple digital clock:
import Tkinter import time curtime = '' clock = Tkinter.Label( ) clock.pack( ) def tick( ): global curtime newtime = time.strftime('%H:%M:%S') if newtime != curtime: curtime = newtime clock.config(text=curtime) clock.after(200, tick) tick( ) clock.mainloop( )
The kind of polling that method after lets you establish is an important Tkinter technique. Several Tkinter widgets have no callbacks to let you know about user actions on them, so if you want to track such actions in real-time, polling may be your only option. For example, here's how to use polling established with after to track a Listbox selection in real time:
import Tkinter F1 = Tkinter.Frame( ) s = Tkinter.Scrollbar(F1) L = Tkinter.Listbox(F1) s.pack(side=Tkinter.RIGHT, fill=Tkinter.Y) L.pack(side=Tkinter.LEFT, fill=Tkinter.Y) s['command'] = L.yview L['yscrollcommand'] = s.set for i in range(30): L.insert(Tkinter.END, str(i)) F1.pack(side=Tkinter.TOP) F2 = Tkinter.Frame( ) lab = Tkinter.Label(F2) def poll( ): lab.after(200, poll) sel = L.curselection( ) lab.config(text=str(sel)) lab.pack( ) F2.pack(side=Tkinter.TOP) poll( ) Tkinter.mainloop( )