In the previous lessons you learned how to associate simple user actions with
the most common user events, such as clicking on a button. For
simple GUI programs this is typically sufficient. But for more complex programs
you might need to process “lower level” events, such as recognizing when
the user’s cursor is over a widget, or when a widget becomes the focus
of user input. To handle these types of events you need to implement
event binding. This lesson provides an overview of how to process any
event that happens on a computer. We will not use these techniques in
most of the simple GUI programs we discuss, but you should be aware of
what is possible.

Remember from our previous discussion that the operating system is in control
of your computer’s screen, keyboard, mouse, and other input devices. When
the user interacts with these input devices the operating system generates
eventobjects that capture specific event information. Your computer is running
multiple processes at any given time, so how does
the computer know which process to send an event to? All GUI operating systems
have the concept of an “active window.” Only the “active window” receives events.
We say that the “active window” has the focus of the user. Typically the
application whose window is in front of all other windows on the computer
screen has the operating system’s focus. Only the process with the focus
receives user events; the other running applications do not receive
user events.

The concept of focus goes further than the applications running on a
computer. Inside an application, only one widget at a time can have the
focus of the user. The widget with the focus is the widget that
receives keyboard events. For example, suppose you had a GUI interface
that contained two different Entry widgets. If the user hits an “a”
key, which widget has an “a” added to their existing text? It is the widget
that currently has the focus.

When your program has the focus it can potentially receive many more
events than it desires to process. For example, you may not care that the
pointing device just moved one pixel to the right. All “low level” user
events are ignored by your program unless you specifically request that
a particular type of event be sent to a specific function in your program.
The task of associating a specific eventhandler function with a specific
“low level” event is called binding.

An event is always bound to a specific widget. For example, if you wanted
to know when the cursor of a pointing device has moved over a widget, you would
bind an "<Enter>" event to the widget and specify a function to call when the
event happens. This is done with the .bind(event_description,event_handler)
method of a widget. Once this bind operation is complete and the
application’s main event loop has started, every time a pointing device is
moved over the widget, the event handler will be called.

It is best practice to “stub out” event handlers and verify that events are
being processed correctly before you start developing an application’s
actual processing code. Here is an example of a “stubbed” out eventhandler:

An event represents an action that needs to be processed. Events are
caused by a user when they click in a window or type on the keyboard.
Events can also be generated by software, such as a request to redraw the
application’s window after changes have been made. In a GUI program,
all processing is done by responding to events.

In Tkinter, events are defined as strings using a pre-defined syntax. The general format
of an event description is <modifier-type-detail>, where the modifier
and detail portions are optional. For example, a <Button> event is
generated by any change of state of any mouse button, while a <Shift-Button>
event will only be generated if the mouse state changes while the SHIFT key
on the keyboard is down. And a <Shift-Button-1> event will only be generated
if the left mouse button (associated with the number 1) changes state.
Below is a list of the most widely used events along with a brief description
of each one. You can add or remove modifier and detail values to make
events more or less specific.

When a user generates an event, or the software generates an event, an eventobject is created. This object is automatically passed to the function that
is registered to handle the event. Every event handler function that is bound
to an event using the .bind(event_description,function_handler) function
must be defined to receive one parameter, an eventobject.

An eventobject contains the following attributes.

Event Object Attribute

Description

.widget

The widget this event was bound to. This is a reference to a
Tkinter widget instance; it is not a string name.

.x, .y

The current mouse position, relative to the application’s window, in pixels.

.x_root, .y_root

The current mouse position relative to the upper left corner of the
screen, in pixels.

.char

For keyboard events only, this is the character code of the key
pressed or released as a string.

The operating system generates events in the order the user or the program
creates them. An application’s GUI event loop receives the events in this
same order and then calls the appropriate event handler. Therefore,
events are processed in the same order they are created.

Events can’t be processed unless the application’s GUI event-loop
is running. If an individual event handler takes a long time to process an
event, other events will get “queued up” waiting for a chance to be processed.
It is considered bad GUI programming for any event handler to take
up too much processing time. An event handler should do as little processing
as possible to accomplish its intended task and then quit. This returns
control of the application back to the event loop.

Events are always associated with a widget. If you want to know every event
that happens inside an application’s window, then bind events to the widget
that is your application’s window. If you only want to know about button
click events on a particular button, then bind an event handler to that
specific button. In general, events should be associated with the most
specific widget possible.

Some widgets, such as a Notebook that implements a tabbed set of frames, have
predefined events that are used to manipulate them. These are called “bind_class”
event bindings and they bind certain events to all instances of a particular
widget type. In general you should not modify or change these types of
event bindings because a user expects a certain behaviour from a particular
type of widget and changing that behaviour can make the entire user interface
confusing to a user.