Events, callbacks, and bindings

Many widgets, such as Button, have available a command option. We have seen an example of this in the simple program at the beginning of this chapter,
use Tk;
use strict;
my $mw = MainWindow->new;
$mw->title('Button');
my $exit = $mw->Button(-text => 'Exit',
                      -command => [$mw => 'destroy']);
$exit->pack;
MainLoop;
where the button associated with $exit has associated with it a callback as a value for the -command option. Callbacks can be specified in a number of ways: for those that don't require arguments, one can use or, for those that need arguments, Subroutines associated with these callbacks are placed after the MainLoop call in the program. We shall see some simple examples of this in the next chapter, and more involved examples in later chapters.

It is possible to bind certain events with callbacks associated with widgets. A common example of this occurs in many programs where, with a click of the right mouse button over an area, a convenient menu of various commands relevant to that portion of the window will pop up. To do this, the bind method is called on a widget; it's syntax is

$widget->bind(sequence,callback)
$widget->bind(tag,sequence,callback)
If no tag is specified then the binding refers to $widget. If tag is specified then it is typically a class name and the bind refers to all instances of the class on the MainWindow associated with $widget. If tag has the value all, then the binding applies to all windows descended from the MainWindow of the application.

The event sequence is specified in the following way:

'<modifier-modifier-type-detail>'
Possible modifiers are listed in the table below - those entries that have two values separated by commas are aliases for one another.


Table 2.1: Possible modifiers
  Control Shift Lock  
Button1, B1 Button2, B2 Button3, B3 Button4, B4 Button5, B5
Mod1, M1 Mod2, M2 Mod3, M3 Mod4, M4 Mod5, M5
Meta, M Alt Double Triple  


In order for a binding to match a given event, all modifiers must match - for example, <Shift-Button-3> will be matched when the third mouse button is depressed at the same time that the shift key is depressed, and <Double-Button-1> is matched with a double click of the first mouse button.

Possible event types appear in the table below, with those entries separated by commas being equivalent.


Table 2.2: Possible event types
ButtonPress, Button ButtonRelease Circulate Colormap Configure
Destroy Enter Leave Activate Deactivate
Expose FocusIn FocusOut KeyPress, Key KeyRelease
Gravity Map Unmap Motion Property
Reparent Visibility      


The last part of the specification of the event is the detail. In the cases of ButtonPress or Buttonrelease, it is the number of the button (eg, <Button-3> specifies the 3rd mouse button). In the cases of KeyPress or KeyRelease, the detail may be specified in the form of an X keysym. Keysyms represent keys on the keyboard - for example, the keysym for the letter ``a'' is itself ``a'', and ``F1'' is the keysym for the ``F1'' function key. These keysyms vary from system to system - consult your system's docuemntation for details of your particular configuration. If a keysym detail is given, as for example <Control-a>, then KeyPress is assumed.

We illustrate bindings with two simple examples. The first,

#!perl
# file bind1.pl
use Tk;
use strict;
use warnings;
my $mw = MainWindow->new;
$mw->title('Bind example');
my $label = $mw->Label(-text => 
                       "Press the 3rd mouse button \nin this area to exit");
$label->bind('<Button-3>', \&say_goodbye);
$label->pack;
MainLoop;
sub say_goodbye {
  print "Goodbye .....\n";
  $mw->destroy;
}
consists of a simple Label widget. This widget is bound to the 3rd mouse button - if the user clicks this button in the area of the label, the callback say_goodbye is called, which simply exits the program. This is illustrated in the figure below.

Figure 2.11: An example of the use of bind
Image bind1

For a second example, we illustrate the feature of some applications that, when the mouse moves over a particular area of a window, a message appears somewhere else in the window with a description of that area. This example is as follows.

#!perl
# file bind2.pl
use Tk;
use strict;
use warnings;
my $default = 'This is the default message';
my $message = $default;
my $mw = MainWindow->new;
$mw->title('Bind example');
$mw->geometry('200x50');
my $label = $mw->Label(-textvariable => \$message);
my $exit = $mw->Button(-text => 'Exit',
                       -command => [$mw => 'destroy']);
$exit->bind('<Enter>',sub {$message = 'Press here to exit';});
$exit->bind('<Leave>',sub {$message = $default;});
$exit->pack;
$label->pack;
MainLoop;
Here the button widget $exit has two bindings - one, associated with <Enter>, is invoked when the user enters the area of the button, and the other, associated with <Leave>, is invoked when the user leaves the area of the button. The callbacks associated with these bindings change the variable $message, which is subsequently displayed by the Label widget of $label. Screenshots of the two states of this window appear below - the figure on the left appears when the cursor is not in the area of the button, and that on the right appears when the cursor is in the button's area.

Figure 2.12: Another example of the use of bind
Image bind2

Randy Kobes 2003-11-17