Sunday, January 20, 2019

Event handling (tkinter)

Tkinter provides an easy and convenient way to handle events by allowing callback functions to be associated with any event and any widget. Very precise events can be directly described and associated with actions. For example, one could decide to only respond to two specific key press events, pressing the tabulation key or the carriage return key.

Tkinter allows to bind distinct callbacks to distinct key press events, in our case one event (and one callback) for the tabulation key and one event for the carriage return key. Thus, Tkinter events do not necessarily correspond to the common event types, but they can be much more specific. Hence this is a great advantage, and allows for a much cleaner implementation.

Tkinter Event Types

The Tkinter event types can be classified into tree major categories:

1. Keyboard events : KeyPress, KeyRelease
2. Mouse events : ButtonPress, ButtonRelease, Motion, Enter, Leave, MouseWheel
3. Window events : Visibility, Unmap, Map, Expose, FocusIn, FocusOut, Circulate, Colourmap,    Gravity, Reparent, Property, Destroy, Activate, Deactivate

Each callback that is bound to an event reveices and an instance of the Event class as parameter when it is invoked. The Event class defines the following properties:

char - pressed character (as a char)(KeyPress, KeyRelease only)
delta - delta of wheel movement (MouseWheel)
focus - boolean which indicates whether the window has the focus (Enter, Leave only)
height - height of the exposed window (Configure, Expose only)
keycode - keycode of the pressed key (KeyPress, KeyRelease only)
keysym - keysym of the the event as a string (KeyPress, KeyRelease only)
keysym_num - keysym of the event as a number (KeyPress, KeyRelease only)
num - number of the mouse button pressed (1=LEFT, 2=CENTER, 3=RIGHT, etc.) (ButtonPress, Button-Release only)
serial - serial number of the event
state - state of the event as a number (ButtonPress, Button-Release, Enter, KeyPress, KeyRelease, Leave, Motion only) or string indicating the source of the Visibility event (one of “VisibilityUnobscured”, “VisibilityPartiallyObscured”,and “VisibilityFullyObscured”
time - time at which the event occurred. Under Microsoft Windows, this is the value returned by the GetTick-Count( ) API function.
type - type of the event as a number
x - x-position of the mouse relative to the widget
x_root - x-position of the mouse on the screen relative to the root (ButtonPress, ButtonRelease, KeyPress, KeyRelease,Motion only)
y - y-position of the mouse relative to the widget
y_root - y-position of the mouse on the screen relative to the root (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion only)
widget - widget for which the event occurred
width - width of the exposed window (Configure, Expose only)

Event Descriptors

In Tkinter, all event handling requires a string description of the event to be bound. Each of these strings can be divided into three sections, and is usually enclosed in angular brackets. The general format is as follows:

<Modifier - Type - Qualifier>

Not all three sections are required in order for an event descriptor string to be valid. In fact, event descriptors only rarely include the three sections. The meaning and the possible values for each section will de discussed next.

1. Type: The type is often the only required section in an event descriptor. It specifies the kind or class of the event. The values that it can take are as follows:

Key - a key is pressed while the widget has the focus
KeyRelease - a key is pressed while the widget has the focus
Button, ButtonPress - a mouse button is pressed on the widget
ButtonRelease - a mouse button is released on the widget
Motion - the mouse is moved over the widget
Enter - the mouse enters a widget
Leave - the mouse leaves a widget
FocusIn - a widget gets the focus
FocusOut - a widget loses the focus
Expose - a widget or part of a widget becomes visible
Visibility - the visibility of a widget or part of a widget changes (the state value is one of “VisibilityUnobscured”,“VisibilityPartiallyObscured”, and “VisibilityFullyObscured”
Destroy - a widget is destroyed
MouseWheel - the mouse wheel is activated over a widget

Other event types include Activate, Circulate, Colormap, Configure, Deactivate, Gravity, Map, Reparant and Unmap.

2. Modifier: The modifier section is optional. If present, it is used to make the event description more precise by requiring that certain keys or mouse buttons should be down while for the event to occur. It can also be used to specify that a particular event has to occur multiple times before its associated callback is executed. There can be more than one modifier specified for an event descriptor, provided that they are seperated by spaces or dashes. Whenever modifiers are present, events must at least match all of the specified modifiers in order for their associated callbacks to be executed. That is, if extra modifiers are present, the callback will still be executed. The values that it can take are as follows:

Any - Event can be triggered in any mode
Alt - Alt key must be down for event to be triggered.
Lock - Caps Lock must be enabled for event to fire.
Control - Control key must be down for event to be triggered.
Meta, M - Meta key must be down for event to be triggered.
Mod1, M1 - Mod1 key should be help down for event to be triggered.
Mod2, M2 - Mod2 key should be help down for event to be triggered.
...
Mod5, M5 - Mod5 key should be help down for event to be triggered.
Shift - Shift key must be down for event to be triggered.
Button1, B1 - Mouse button 1 should be help down for event to be triggered.
Button2, B2 - Mouse button 2 should be help down for event to be triggered.
...
Button5, B5 - Mouse button 5 should be help down for event to be triggered.
Double - The event should occur twice (in a short time period) before its callback is executed.
Triple - The event should occur three times (in a short time period) before its callback is executed.

3. Qualifier: The qualifier can be any integer from 1 to 5, in which case it specifies a mouse button. Mouse buttons are numbered from 1 to 5 starting from the left button (left = 1, center = 2, right = 3, etc.). It can also be a keysym. Keysyms are names attributed to specific keys, such as “backslash” or “backspace”.Whenever a qualifier is specified, the type is not strictly required. It is omitted, then the
default type will be KeyPress for keysym qualifiers and ButtonPress for mouse button qualifiers.

The event descriptor “< keysym >” is equivalent to “keysym” (without the angular brackets), provided that keysym is not a space or an angular bracket. Some example of common event descriptors are:

<Any-Enter>  Triggered when the mouse enters a widget
<Button-1>, <1> Triggered when a left click is done in a widget
<B1-Motion> Triggered when the mouse is dragged over the widget with the left mouse button being
held down.
<Double-Button-1> Triggered when a widget is double-clicked with the left mouse button
<Key-A>, <KeyPress-A>, <A>, A Triggered when the key producing the letter A (caps) is pressed.

Binding Callbacks to Events

For the application to be able to respond to events, methods or functions have to be associated with events, so that they are called whenever the events occur. These methods and functions are referred to as callbacks. Binding is the process by which a callback is associated to an event by means of an event descriptor.

There are 3 methods that can be used to bind events to widgets in Tkinter:

1. The bind() method, which can be called on any widget, and in particular a Toplevel widget (Tkinter makes a difference between Toplevel widgets and other widgets)

2. The bind class() method, which binds events to a particular widget class. This is used internally in order to provide standard bindings for Tkinter widgets. This function should usually be avoided, as it can often be replaced by implementing a descendant of the particular widget, and by binding it to the desired callback.

3. The bind all() method, which binds events for the whole application. The bind() method is declared as follows:

bind(self, sequence=None, func=None, add=None)

where sequence is an event descriptor (as a string), func is the name of the function to be associated with the event (ie the callback), and add is a boolean which specifies that func should be called in addition to the current callback for this event instead of replacing it. This method returns a function ID which can be used with unbind to remove a particular binding. The unbind method is defined as follows:

unbind(self, sequence, funcid=None)

Similarly, the bind class() method is defined as follows:

bind class(self, className, sequence=None, func=None, add=None)

and has its associated unbind class method which is defined as follows:

unbind class(self, className, sequence) 

Finally, the bind all() method is defined as follows:

bind(self, sequence=None, func=None, add=None)

while the unbind all() method is defined as follows:

unbind class(self, sequence=None)

The callbacks will receive an Event object as parameter, so they must include this object in their parameter list. The Event object should be the first parameter for callbacks which are not part of a class, and the second parameter for class methods (since the class reference, self, is always the first parameter).

When an event occurs in Tkinter, the event callbacks are called according to their level of specificity. The most specific event handler is always used, the others are not called (eg when Return is pressed, a callback associated with the <Return> event will be executed and one associated with the <KeyPress> event will not be called in the case where both have been bound to the same widget). Moreover, the callbacks for the 4 different levels of Tkinter’s event handling will be called in sequence, starting with the widget level, then the Toplevel, the class and then the Application.

If, at a given level, the callback handling must stop, the callback should return the string “break”. This will prevent any other callbacks from being executed for a given event. This is especially useful for overriding default behaviour of certain keys (eg.backspace and tab) which occur at the application level.

Here I am ending today's topic, till we meet next, keep practicing and learning Python as Python is easy to learn!



Share:

2 comments: