14—
Binding Events
Perl/Tk is an event-driven programming language. You design your program to respond to events generated by the program. Event sequences can be pushing a button, moving the mouse, or typing some characters with a keyboard. The relationship between the event sequence and the widget is called a binding.
Each widget provided with Perl/Tk has its own default bindings. For example, the button widget changes color when the mouse pointer is over the button and it invokes a callback that you specified when it is clicked. These are default bindings, ones that are created when you create the widget itself.
You can have your program respond to additional events by using the bind command to assign callbacks to different event sequences; the basic format is:
$widget->bind(sequence, callback);
In addition, you can override the default bindings by creating your own or just removing them.
The bind Method
To use the bind method, invoke it from the widget to which you would like to add the binding. For instance, if you want to add a binding to a button in $button, use $button->bind. In certain instances, you would use the main window
of your application: $mw->bind(...). There are several different sets of valid arguments you can send to bind. The following list explains them all:
$widget->bind();
Calling bind with no arguments returns a list of bind sequences (e.g. <Button-1>, <Key-D>) that have been created for that widget. It will not return any of the default bindings. Here's an example:
$button = $mw->Button( ... )->pack;
$button->bind("<Button-3>", sub { ... } );

@bindings = $button->bind();
print "Bindings for button :@bindings\n";
# would print:
# Bindings for button: <Button-3>
This function will return an empty string if there are no additional bindings for that widget.
$widget->bind (sequence);
You can determine what callback is associated with a bind sequence. Pass in the bind sequence (for example,
"<Button-3>") as the first argument and the currently assigned callback will be returned. Expanding the preceding example, we can use the information in @bindings to see what callbacks are associated with them:
foreach (@bindings) {
  print "$_ is assigned callback ", $button->bind($_), "\n";
}
# <Button-3> is assigned callback Tk::Callback=CODE(0×91fdcc)
If you send a bind sequence that doesn't exist for that widget, you'll simply get an empty string as the result. Also, if you use a sequence that is considered a default binding (for example, "<Button-1>" on a button widget), you'll get an empty string as well (unless you've added another binding to it with bind).
$widget->bind (sequence, callback);
To have a callback invoked when a sequence happens, specify it after the sequence in the
bind call. It can be any of the valid forms for callbacks discussed in Chapter 3. Here are a few examples:
$button->bind("<Button-3>", sub { print "Right clicked\n" });
$entry->bind("<Return>", sub { print "Hit return in entry widget\n" });
$button->bind("<Button-1>", \&b1_addtl_action());
$canvas->Tk::bind("<Button-1>", [ \&draw_rectangle, Ev("X"), Ev("Y") ]);
To remove a binding for a specific sequence, send an empty string for the callback.
$widget->bind (tag [, sequence, callback ] );
A tag is a way to refer to a widget class. You use tags if you wanted every widget of a certain type to have the same behavior. For instance, if you want a search menu to pop up when you right-click in the text widget, you can do this:
$t1 = $mw->Scrolled("Text")->pack(-expand => 1, -fill => 'both');
$t2 = $mw->Scrolled("Text")->pack(-expand => 1, -fill => 'both');

$menu = $mw->Menu(-menuitems => [ ["command" => "Search",
                                   -command => \&search_file],
                                  ["command" => "Search Again",
                                   -command => \&search_again]
                                 ],
                         -tearoff => 0);
$mw->bind(Tk::Text, "<Button-3>",
          sub { $menu->Popup (-popover => 'cursor'
                            -popanchor => "nw") });
Any text widgets you create inside the application would then have the search menu pop up over it. You would have to do a little work in the search routines to determine which text widget triggered the function, but you wouldn't have to recode the same bind sequence for each text widget you create.
In the preceding example, we specified the sequence ("<Button-3>") to be bound. If we didn't, we would get a list of the current callbacks associated with that event sequence.
The special tag 'all' can be used to refer to every widget and window in the application. But be careful; you'll get much more activity in your callback than you would think!
Arguments Sent to the Callback
The first argument to a callback assigned with bind is always a reference to the calling widget. This is true even when you bind to a widget class. You can use the reference passed in to retrieve information about the widget from which the sequence was invoked.
Here's an example of using a single entry widget:
$entry = $mw->Entry()->pack;
$entry->bind("<Return>", \&hit_return);
sub hit_return {
  my ($e) = @_;
  print "Entry contained: ", $e->get, "\n";
}
When you use bind to invoke a callback on an entire widget class, it makes the job of determining which widget was the subject of the event much easier:
$mw->Scrolled("Text")->pack(-expand => 1, -fill => 'both');
$mw->Scrolled("Text")->pack(-expand => 1, -fill =>'both');

$menu = $mw->Menu (-menuitems =>[ ["command" => "Save",
                                    -command => \&save_file],
                                   ["command" => "Open",
                                   -command => \&open_file]
                                  ],
                             -tearoff => 0);
$mw->bind(Tk::Text, "<Button-3>",
          sub {$menu->Popup(-popover => 'cursor') });
sub save_file {
  my ($text) = @_;
  open(FH, ">outfile") || die "Couldn't open outfile for writing";
  print FH $text->get("1.0", "end");
  close (FH);
}
The call to bind uses Tk: :Text as the first argument. This will cause the bind to be applied to every text widget in the application. In this example, no matter which text widget is clicked, its contents will be written to "outfile". The application might also prompt the user for a different filename at that point, allowing it to actually do something useful.
Defining Event Sequences
So far, you've seen several different event sequences-<Button-3>, <Button-1>, and <Return>-but I haven't yet explained the format for building them. Although the examples you've seen may seem obvious and simple, event sequences can get much more complicated.
The event sequence is built from an optional modifier, an event, and an optional detail. They are separated by dashes and then placed between angle brackets:
<modifier-event-detail>
As we discuss all the possible bindings, keep in mind that it is possible for more than one event sequence to match. The more detailed matches will invoke their callbacks first. If a binding has been created on a specific button, and then another binding is created on all of the buttons, the specific-button bind callback will be invoked first, and then the more general all-button bind callback will be invoked.
Modifiers
A modifier is an event that happens at the same time the main event happens, such as holding down the Control key and clicking the mouse. The modifying
event must happen first in order for the entire event sequence to match (e.g., pressing the Control key and then pressing the mouse button).
The possible modifiers and their meanings are as follows:
Control
The Control key must be pressed down as the main event is happening (e.g.,
<Control-Button-1>).
Shift
The Shift key must be pressed down as the main event happens (e.g.,
<Shift-Button-3>).
Lock
The Caps Lock key must be pressed to turn on caps lock (e.g.,
<Lock-Key-a>).
Alt
Causes the main event to match only if either of the Alt keys is pressed down while the main event happens (e.g.,
<Alt-Key-x>).
Microsoft Windows users should be aware that sometimes MS Windows doesn't allow the event notifier to notify applications that the left Alt key has been pressed. The left Alt key is normally the Alt key people use when switching between applications by using ALT-Tab. If the left Alt key doesn't work, try the right one before giving up. This warning also applies if you are using an X Window server (e.g., Exceed) on MS Windows to access a Unix system.
Button# where # is 1, 2, 3, 4, or 5. You could also use B# as a shortcut.
These modifiers indicate that, before the rest of the event happens, the specified mouse-button number must be depressed. For instance, if you want to trigger an event when the user clicks mouse button 1 and then mouse button 3, you can use the event
<Button1-Button-3> (or <B1-Button-3>). The same event would not be triggered if you clicked mouse button 3 and then mouse button 1. The events are order dependent.
It is not valid to use only <Button#> because, without the dash between "Button" and the number, you are indicating a modifier to another event type.
Double
Double is a special type of modifier that indicates the main event should happen twice. Double puts a constraint on the minimum amount of time between the repetitions of the main event. Double is most often used to indicate a double-click of a mouse button.
It is important to note that <Double-Button-1> is not equivalent to <Button-1><Button-1>. Although they sort of mean the same thing, there is no
time constraint with the <Button-1><Button-1> event. The second means "You clicked button 1, and then at some later point, you clicked button 1 again." The <Double-Button-1> event means "You clicked button 1, and within a certain time period, you clicked button 1 again."
Triple
Similar to Double, Triple is another special modifier type. It requires that themain event occur three times in rapid succession.
Another interesting thing to consider with Double and Triple modifiers is that they are cumulative. If you click five times quickly on a button, the first click would match at <Button-1> event, the second click would match a <Double-Button-1> event, the third click would match Triple-Button-1> event, and the fourth click would also match a <Triple-Button-1>event, and so on. This is true only if the <Triple-Button-1> event is defined. If only <Double-Button-1> is defined, the third click would reactivate that binding instead of the <Triple> binding. The timeline in Figure 14-1 shows when the events are generated.
0275-01.gif
Figure 14-1.
Cumulative double-clicking example
Meta (or M)
Requires that the Meta key be pressed during the main event. The Meta key is usually used on X Window Systems only.
Mod#or M#
This is also only used on X Window Systems. There are several modifiers (1-5); use
Ev('K') to determine where they are on your keyboard.
Event Types (with Optional Details)
The event portion of the event string is the event we are looking for. It can have a modifier or not (as specified in the preceding section). When the information says an event is triggered or generated, it means that the event has happened. If there is no callback associated with the event, it will look as if nothing has actually happened. The following is a list event types and the optional details where applicable.
ButtonPress (or Button)
A ButtonPress happens when a mouse button is pressed down. The Button event also refers to a ButtonPress; it's just a shorter way to write it. If you use the event
<Button>, it refers to any mouse button, but you can specify a specific button by adding a detail: <Button-1>, <ButtonRelease-2>, and so on.
ButtonRelease
A ButtonRelease event happens when the mouse button is released. You can have different things happen based on the button being pressed down (Button or ButtonPress) and let up (ButtonRElease). You can spcify a detail to indicate a different button:
<ButtonRelease-1, <ButtonRelease-2>, and so on. If a specific button isn't specified, any button will match the event.
Circulate
The Circulate event is generated when your application has more than one window and the stacking order is switched around.
Colormap
The Colormap event happens when the colormap for the widget (usually a toplevel) has changed.
Configure
The Configure event happens when a widget is configured. If you map a callback to this one, be careful; it can be called quite often. Every time the application window is resized, each widget within the window is configured, resulting in a Configure event being generated for those widgets. When the widget is first created, it also generates a Configure event.
Destroy
When the widget is destroyed, the Destroy event is generated. You can forcefully destroy a widget by using
$widget->destroy().
Enter
The Enter event happens when the mouse cursor enters the area occupied by the widget. It is important to remember that this is not the ''user-presses-the-RETURN/Enter-keyboard-key" event.
Expose
The Expose event happens when the window has been exposed.
FocusIn
When the widget receives the keyboard focus because the user has tabbed to it (or
$widget->focus() happens in the program), the FocusIn event happens.
FocusOut
The FocusOut event is the opposite of FocusIn. When the keyboard focus leaves the widget, FocusOut is triggered.
Gravity
The Gravity event happens when the widget moves because the widget's parent changed size.
KeyPress (or Key)
When a key on the keyboard is pressed, the KeyPress (or Key) event is generated. It is possible to narrow this down to the specific key such as the "a" key by using a detail with the event:
<Key-a>. If you want to determine which key was pressed to trigger the event, you can use Ev('K') as an argument with your callback:
$mw->bind("<Key>", [ \&check_key, Ev ('K') ]);
This has the effect of sending the key symbol for the key pressed as an argument to check_key. To find out which key symbols are for which keys, use this piece of code:
use Tk;
$mw = MainWindow->new;
$mw->bind("<Key>", [ sub { print "Key: $_[1]\n"; }, Ev('K')] );
MainLoop;
As you press keys on the keyboard, you'll see their key symbols printed out on the screen. Notice that the shift characters above the numbers (such as $, %, Ù, and so on) come out as named ("dollar,", "percent," ''caret,", and so on).
KeyRelease
The KeyRelease event is the companion event to KeyPress. It is invoked when the key is released. Sometimes it is preferable to wait until the key has been released before doing anything.
Leave
The Leave event happens when the mouse cursor leaves the area occupied by the widget. Use Enter and Leave events to create two bindings for the same widget and you can do neat things such as change the mouse cursor while the mouse is in the widget (look into using
-cursor first if it's available for that widget).
Map
The Map event happens when window has been mapped or opened (deiconified).
Motion
When the mouse moves around on the screen above your application, it generates a Motion event. This is another event that you don't want to bind to lightly because your callback will be triggered all the time. Granted, if you bind to just a single widget, you'll only get Motion events when you are passing over that widget, but that is still a lot of invocations of the callback. I suggest having a very good reason for binding to the Motion event.
Reparent
The Reparent event happens when parent of the bound widget has changed.
Unmap
The Unmap event happens when the bound window has been iconified.
Visibility
When a widget first becomes visible, it triggers the Visibility event. There are several ways a widget becomes visible in your application:
• When the application first starts up, and the widget is placed on the screen, it triggers a Visibility event. Note that if you create a widget and don't pack it onto the screen, a Visibility event will not be generated.
• When the widget is unpacked by using pack ('forget') and then repacked.
• When the window is resized and the widget suddenly comes into view (usually after the window has been made smaller and then resized larger).
• When the widget is inside another widget (such as a text or canvas widget) and scrolls back on the screen.
Event Information
You can find out information about an event by using the Ev method. There are many values you can use in a call to Ev, and they are thoroughly documented on the Perl/Tk documentation web site at http;//w4.lns.cornell.edu/~pubp/ptk/doc/bind.btm, which is maintained by Peter Prymmer, and http://www.perl.com/ ptk/pod/bind.pod.. I'll cover the values that you would want to use 99.9 percent of the time. Remember that certain values used with Ev are only valid for certain events. If you use an Ev value that doesn't apply, you'll get an undefined value.
Coordinates
To determine the coordinates at which the event happened, use Ev('x') and Ev('y'). They return coordinates relative to the window in which the event happened. If you want coordinates relative to the root of your window system (desktop in Windows, Xroot in X), use uppercase X and Y: Ev('X') and Ev('Y').
Ev('X') and Ev('Y') are valid only for ButtonPress, ButtonRelease, KeyPress, KeyRelease, or Motion events.
Button Number
To find out which button number on the mouse was pressed, use Ev('b'). It is valid only for ButtonPress or ButtonRelease events. If you use Ev('b') with a <Button-1> event, you would obviously get 1 back.
Height and Width
Use an 'h' to return the height and a 'w' to return the width associated with the event. The width and height returned indicate how large the widget is. For instance, if you want to find out the new size of a button after the window has been manually resized by the user, you can do this:
$button->bind("<Configure>", [ sub { print "H: $_[1], W: $_[2]\n"; },
                               Ev('h'), Ev('w') ]);
The callback will only be invoked when the widget has been configured. This happens when the widget is first created and any time the widget is resized.
Ev('h') and Ev('w') are valid only for Configure, Expose, and GraphicsExpose events.
Keyboard Information
There are several ways to find out which keys the user has pressed on the keyboard. Use 'K' to print out the value associated with that keycalled a keysym. If you use lowercase 'K' you'll get the ASCII value associated with the key. Try this bit of code to see the difference:
$b->bind("<Key>", [ sub { print "ARGS: @_\n" }, Ev('K') ]);
Ev('k') and Ev('K') are valid only for KeyPress and KeyRelease events.
You can also get the keysym as a decimal number rather than a string by using Ev('N').
Event Type
You can find out what type of event the callback is responding to by using Ev('T'). When responding to a KeyPress event, the string will be "KeyPress". It's pretty obvious, but sometimes it's useful if you are using the same callback to respond to several different events.
Bailing Out of a Callback Created with bind
To stop the processing within your callback, you can use a return statement to return control. This will not stop any further bound callbacks from being processed. To halt the processing of any and all callbacks bound to a widget/event combination, you can use Tk::break instead of the milder return.
The bindtags Method
To find out the tags associated with a widget, use the bindtags method; for example:
print join(' ', $button->bindtags()) ;
# prints this: Tk::Button .button . all
print join(' ', $mw->bindtags()) ;
#prints this: MainWindow . all
This tells us the order in which the widget will respond to binding callbacks. The first response is always to the class that the widget belongs to; Tk::Button in the first example and MainWindow in the second.
The information returned from bindtags isn't nearly as interesting as what you can do with arguments sent to it. To remove all specific bindings from a widget except those that apply to 'all'
$button->bindtags (['all']);
Now the button will not respond to being pressed, mouse movements, or the default bindings associated with the widget. As demonstrated in the Perl/Tk web page for bindtags, you can reverse the order in which the widget responds to events like this:
$b->bindtags(['all' ,$b->toplevel,ref($b),$b]);
We already know that 'all' means any bindings associated with the special 'all' bindtag. Using $b->toplevel returns the window $b lives in: MainWin-dow=HASH(Ox9798d8). Using ref($b) gives the package $b belongs to: Tk::Button. Finally, $b means the specific instance of $ b: Tk::Button=HASH(Ox99c0cc).
HASH(Ox99cOcc) is a what we see when we print the value out. The hex number in parentheses is just the physical memory location of that widget. HASH means that it is stored in a hash structure.
Ways to Use bind
Using bind is a powerful way to make your application do things easily. You can add a binding to a listbox widget so it will display a menu when you right-click on it. Use bind with text tags to create a pseudo-html document. Add a double-click binding to the listbox so that something happens when a user double-clicks on an item in the listbox. There are more ways you can use bind than I could ever cover here. Just make sure you don't do anything that the user can't figure out (for example, triple-clicking while holding down the Control key is a bit obscure).