www.gibmonks.com

  Previous section   Next section

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 26.  Binding Commands to Events


Event Syntax

The bind command uses the following syntax to describe events:

<modifier-modifier-type-detail>
<<Event>>

The first form is for physical events like keystrokes and mouse motion. The second form is for virtual events like Cut and Paste, which correspond to different physical events on different platforms. Physical events are described in this section. Virtual events are described in more detail on page 378.

The primary part of the description is the type, (e.g., Button or Motion). The detail is used in some events to identify keys or buttons, (.e.g., Key-a or Button-1). A modifier is another key or button that is already pressed when the event occurs, (e.g., Control-Key-a or B2-Motion). There can be multiple modifiers (e.g., Control-Shift-x). The < and > delimit a single event.

Table 26-1 on the next page lists all physical event types. When two event types are listed together (e.g., ButtonPress and Button) they are equivalent.

Keyboard Events

The KeyPress type is distinguished from KeyRelease so that you can have different bindings for each of these events. KeyPress can be abbreviated Key, and Key can be left off altogether if a detail is given to indicate what key. Finally, as a special case for KeyPress events, the angle brackets can also be left out. The following are all equivalent event specifications:

<KeyPress-a>
<Key-a>
<a>
a

The detail for a key is also known as the keysym, which refers to the graphic printed on the key of the keyboard. For punctuation and non-printing characters, special keysyms are defined. Case is significant in keysyms, but unfortunately there is no consistent scheme. In particular BackSpace has a capital B and a capital S. Commonly encountered keysyms include:

Return, Escape, BackSpace, Tab, Up, Down, Left, Right, comma, period, dollar, asciicircum, numbersign, exclam.

Table 26-1. Event types.
ActivateThe application has been activated. (Macintosh)
ButtonPress, ButtonA button is pressed (down).
ButtonReleaseA button is released (up).
CirculateThe stacking order of the window changed.
ColormapThe color map has changed.
ConfigureThe window changed size, position, border, or stacking order.
DeactivateThe application has been deactivated. (Macintosh)
DestroyThe window has been destroyed.
EnterThe mouse has entered the window.
ExposeThe window has been exposed.
FocusInThe window has received focus.
FocusOutThe window has lost focus.
GravityThe window has moved because of a change in size of its parent window.
KeyPress, KeyA key is pressed (down).
KeyReleaseA key is released (up).
MouseWheelThe scrolling mouse wheel has moved.
MotionThe mouse is moving in the window.
LeaveThe mouse is leaving the window.
MapThe window has been mapped (opened).
PropertyA property on the window has been changed or deleted.
ReparentA window has been reparented.
UnmapThe window has been unmapped (iconified).
VisibilityThe window has changed visibility.

graphics/tip_icon.gif

Finding out what keysyms are generated by your keyboard.


There are times when you do not know what keysym is generated by a special key on your keyboard. The keysyms are defined by the window system implementation, and on UNIX systems they are affected by a dynamic keyboard map, the X modmap. You may find the next binding useful to determine just what the keysym for a particular key is on your system:

bind $w <KeyPress> {puts stdout {%%K=%K %%A=%A}}

The %K keyword is replaced with the keysym from the event. The %A is replaced with the printing character that results from the event and any modifiers like Shift. The %% is replaced with a single percent sign. Note that these substitutions occur in spite of the curly braces used for grouping. If the user types a capital Q, there are two KeyPress events, one for the Shift key, and one for the q key. The output is:

%K=Shift_R %A={}
%K=Q %A=Q

The Shift_R keysym indicates the right-hand shift key was pressed. The %A keyword is replaced with {} when modifier keys are pressed. You can check for this in <KeyPress> bindings to avoid doing anything if only a modifier key is pressed. On Macintosh, there is no event at all when the modifier keys are pressed. The following can be used with a text widget. The double quotes are necessary to force a string comparison:

bind $w <KeyPress> {
     if {"%A" != "{}"} {%W insert insert %A}
}

Mouse Events

Button events also distinguish between ButtonPress, (or Button), and ButtonRelease. Button can be left off if a detail specifies a button by number. The following are equivalent:

<ButtonPress-1>
<Button-1>
<1>

Note: The event <1> implies a ButtonPress event, while the event 1 implies a KeyPress event. To avoid confusion, always specify the Key or Button type.

The mouse is tracked by binding to the Enter, Leave, and Motion events. Enter and Leave are triggered when the mouse comes into and exits out of the widget, respectively. A Motion event is generated when the mouse moves within a widget.

The coordinates of the mouse event are represented by the %x and %y keywords in the binding command. The coordinates are widget-relative, with the origin at the upper-left hand corner of a widget's window. The keywords %X and %Y represent the coordinates relative to the screen:

bind $w <Enter>  {puts stdout "Entered %W at %x %y"}
bind $w <Leave>  {puts stdout "Left %W at %x %y"}
bind $w <Motion> {puts stdout "%W %x %y"}

A mouse drag event is a Motion event that occurs when the user holds down a mouse button. In this case the mouse button is a modifier, which is discussed in more detail on page 375. The binding looks like this:

bind $w <B1-Motion> {puts stdout "%W %x %y"}

Other Events

The <Map> and <Unmap> events are generated when a window is opened and closed, or when a widget is packed or unpacked by its geometry manager.

The <Activate> and <Deactivate> events are generated when an application is activated by the operating system. This applies to Macintosh systems, and it occurs when the user clicks in the application window.

The <Configure> event is generated when the window changes size. A canvas that computes its display based on its size can bind a redisplay procedure to the <Configure> event, for example. The <Configure> event can be caused by interactive resizing. It can also be caused by a configure widget command that changes the size of the widget. You should not reconfigure a widget's size while processing a <Configure> event to avoid an indefinite sequence of these events.

The <Destroy> event is generated when a widget is destroyed. You can intercept requests to delete windows, too. See also the description of the wm command on page 569.

The <MouseWheel> event is generated on Windows by the small scrolling wheel built into the Microsoft Mouse. It reports a delta value using the %D keyword. Currently the delta is an integer multiple of 120, where positive values indicate a scroll up, and negative values indicate a scroll down.

Chapter 36 presents some examples that use the <FocusIn> and <FocusOut> events. The remaining events in Table 26-1 have to do with dark corners of the X protocol, and they are seldom used. More information can be found on these events in the Event Reference section of the Xlib Reference Manual (Adrian Nye, O'Reilly & Associates, Inc., 1992).

Bindings on Top-level Windows

graphics/tip_icon.gif

Bindings on toplevels are shared by widgets they contain.


Be careful when binding events to top-level windows because their name is used as a binding tag on all the widgets contained in them. For example, the following binding fires when the user destroys the main window, which means the application is about to exit:

bind . <Destroy> {puts "goodbye"}

Unfortunately, all widgets inside the main window are destroyed as a side effect, and they all share the name of their toplevel widget as a binding tag. So this binding fires when every widget inside the main window is destroyed. Typically you only want to do something one time. The following binding checks the identity of the widget before doing anything:

bind . <Destroy> {if {"%W" == "."} {puts "goodbye"}}

      Previous section   Next section
    Top