Advanced Perl Programming

Advanced Perl ProgrammingSearch this book
Previous: 14.5 TimersChapter 14
User Interfaces with Tk
Next: 14.7 Event Loops
 

14.6 Event Bindings

An event binding associates a callback function with any type of event. You have already seen instances of event bindings - the button widget's command property arranges for a user-defined procedure to be called on a mouse click, for example. The bind() command provides a more general (and hence low-level) access to the most fundamental events such as keyboard and mouse button presses and releases. (A mouse click is a press and release, so we are talking about really low-level events here.) Other "interesting" event types include mouse motion, the mouse pointer entering or leaving a window, and windows getting mapped or resized on the display. All widgets themselves rely on the bind method for their own functionality, and allow you to create extra bindings yourself. The bound procedure executes if the event you're tracking happens inside that widget or is related to that widget (such as a window resize).

The syntax of bind is as follows:

$widget->bind(event sequence, callback);

The event sequence is a string containing a sequence of basic events, with each basic event contained in angle brackets. Examples of event sequences are as follows:

"<a>"                   # Key "a" pressed (Control/shift/meta not
                        # pressed)
"<Control-a>            # Control and a pressed
"<Escape> <Control-a>"  # Two-event sequence
"<Button1>"             # Mouse button 1 clicked
"<Button1-Motion>"      # Mouse moves while Button 1 is down

A single event (within angle brackets) has the following generic syntax:

"<modifier-modifier...-modifier-type-detail>" 

Examples of modifiers are Control, Meta, Alt, Shift, Button1 (or B1), Button2, Double (double click), and Triple. The modifier Any is a wildcard - all possible modifiers (including none of them) match the basic event.

The type of the event is one of KeyPress, KeyRelease, ButtonPress (or Button), ButtonRelease, Enter, Leave, and Motion.

For keyboard event specifications, the detail is a textual string describing the exact key. X Windows calls this a keysym. For printable ASCII characters, the keysym is the printed character itself. Other examples of keysyms are Enter, Right, Pickup, Delete, BackSpace, Escape, Help, F1 (function key), and so on.

The most common event types are key presses and button clicks, so Tk allows an abbreviated form of binding: instead of saying <KeyPress-a>, you can say, <a>; instead of writing <Button1-ButtonPress>, you can say, <1>.

The text and canvas widgets support bindings at a finer level of granularity. They support event bindings for different tags in addition to bindings for the widget itself. bind allows you to specify the name of the tag as the first parameter and the event sequence and callback as the second and third parameters, respectively:

$text->bind('hyper-link', '<1>', \&open_page);

This code ensures that any stretch of text tagged with "hyper-link" will respond to a button click event and call the procedure open_page.

14.6.1 Multiple Bindings

It is possible to have several bindings to respond to the same event. For example, when a mouse button is pressed, both <Button1> and <Double-Button1> are candidates. If there's a conflict for a given widget (or tag), the rule is that the most specific binding is called. <Double-Button1> is more specific than <Button1>, since it is a longer specification.

In addition to matching the most specific binding at the widget level, Tk matches the most specific bindings at the class level (the class that represents all buttons, for example), then at the widget's top level, then at a level called "all." All four categories of bindings are executed. This order itself can be changed using the bindtags() method, but I recommend that you avoid doing this.

Although Tk allows you to change default widget bindings, I recommend that you don't modify them because people get used to them working in a certain way. For example, a double-click inside a text widget usually selects the word under the mouse pointer, and it would be quite disconcerting for a user if you happened to change that behavior. On the other hand, there are plenty of other places where you can, and need to, add your own bindings. Canvas and text widget tags are the most frequent target of event bindings, as we shall see in the next two chapters.

14.6.2 Event Details

We have seen how to specify an event accurately. There are times when we do exactly the opposite - make the event specifier most general, such as <Any-KeyPress>. For instance, you probably don't want to specify a unique binding for each character on the keyboard. But when a key is pressed, the callback might like to know which key was pressed. This is where event details come in.

Each event carries with it all the details related to that event, and the function Ev() is used to get at those details. The parameter to Ev() is a single character that specifies the part of the event record you are interested in. Ev('k') specifies the keycode, Ev('x') and Ev('y') specify the x and y coordinates of the mouse pointer, and Ev('t') specifies the time of the event. There are over 30 such parameters to Ev. The following example shows how you can use this facility:

$label->bind("<Any-KeyPress>" => [\&move, Ev('k')]);
sub move {
    my $key = shift;
    if ($key eq 'k') {
       move_left();
    } elsif ($key eq 'l') {
       move_right();
    }
}

In this example, the bind specification registers its interest in key events and specifies that it wants the keycode supplied to the callback procedure whenever it is invoked.


Previous: 14.5 TimersAdvanced Perl ProgrammingNext: 14.7 Event Loops
14.5 TimersBook Index14.7 Event Loops