So far we have covered the widgets types, how instances of them are created, how their attributes can be set and queried, and how they can be managed for display using geometry managers. What we have not touched on is how to give each widget a behavior.
This is done through event handlers. Each widget instance can be given a window event handler for each kind of window event. A window event is something like the cursor moving into or out of the widget, a key press happening while the widget is active (in focus), or the widget being destroyed.
Event handlers are specified through the bind
command:
bind widgetName eventSequence command
where widgetName is the name or class of the widget to which the event handler should be attached, eventSqueuence is a description of the event that this event handler will handle, and command is a script that is invoked when the event happens (i.e. it is the event handler).
Common event types are
Key
KeyPress
KeyRelease
Button
ButtonPress
ButtonRelease
Enter
Leave
Motion
There are other event types. Please refer to the Tk documentation for a complete list.
The eventSequence part of a bind command is a list of one or more of these events, each event surrounded by angled brackets. (Mostly, an event sequence consists of handling a single event. Later we will show more complicated event sequences.)
An example is the following:
button .b -text "click me" pack .b bind .b <Enter> { puts "entering .b" }
makes a button .b
displaying text click me
and displays it in
the root window using the packing geometry manager. The bind
command
specifies that when the cursor enters (i.e. goes onto) the widget, then
the text entering .b
is printed at the terminal.
We can make the button change color as the cursor enters or leaves it like this:
button .b -text "click me" -background red pack .b bind .b <Enter> { .b config -background blue } bind .b <Leave> { .b config -background red }
which causes the background color of the button to change to blue when the cursor enters it and to change back to red when the cursor leaves.
An action can be appended to an event handler by prefixing the action with
a +
sign. An example is:
bind .b <Enter> {+puts "entering .b"}
which, when added to the example above, would not only change
the color of the button to red when the cursor enters it, but would
also print entering .b
to the terminal.
A binding can be revoked simply by binding the empty command to it:
bind .b <Enter> {}
A list of events that are bound can be found by querying the widget thus:
bind .b
which will return a list of bound events.
To get the current command(s) bound to an event on a widget, invoke
bind
with the widget name and the event. An example is:
bind .b <Enter>
which will return a list of the commands bound to the event <Enter>
on widget .b
.
Binding can be generalized to sequences of events.
For example, we can create an entry widget that
prints spells rob
each time the key sequence ESC r o b
happens:
entry .e pack .e bind .e <Escape>rob {puts "spells rob"}
(A letter on its own in an event sequence stands for that key being pressed when the corresponding widget is in focus.)
Events can also be bound for entire classes of widgets. For example, if we wanted to perform the same trick for ALL entry widgets we could use the following command:
bind entry <Escape>rob {puts "spells rob"}
In fact, we can bind events over all widgets using all
as
the widget class specifier.
The event script can have substitutions specified in it. Certain
textual substitutions are then made at the time the event is
processed. For example, %x
in a script gets the x coordinate of
the mouse substituted for it. Similarly, %y
becomes the y
coordinate, %W
the dot path of the window on which the event
happened, %K
the keysym of the button that was pressed, and so
on. For a complete list, see the manual.
In this way it is possible to execute the event script in the context of the event.
A clever example of using the all
widget specifier and text
substitutions is given in John Ousterhout's book on Tcl/Tk (see Resources):
bind all <Enter> {puts "Entering %W at (%x, %y)"} bind all <Leave> {puts "Leaving %W at (%x, %y)"} bind all <Motion> {puts "Pointer at (%x, %y)"}
which implements a mouse tracker for all the widgets in a Tcl/Tk application. The widget's name and x and y coordinates are printed at the terminal when the mouse enters or leaves any widget, and also the x and y coordinates are printed when the mouse moves within a widget.