Read Programming Python Online

Authors: Mark Lutz

Tags: #COMPUTERS / Programming Languages / Python

Programming Python (59 page)

BOOK: Programming Python
2.71Mb size Format: txt, pdf, ePub
ads
Binding Events

We met the
bind
widget
method in the prior chapter, when we used it to catch button
presses in the tutorial. Because
bind
is commonly used in conjunction with other widgets (e.g., to catch return
key presses for input boxes), we’re going to make a stop early in the tour
here as well.
Example 8-15
illustrates more
bind
event
protocols.

Example 8-15. PP4E\Gui\Tour\bind.py

from tkinter import *
def showPosEvent(event):
print('Widget=%s X=%s Y=%s' % (event.widget, event.x, event.y))
def showAllEvent(event):
print(event)
for attr in dir(event):
if not attr.startswith('__'):
print(attr, '=>', getattr(event, attr))
def onKeyPress(event):
print('Got key press:', event.char)
def onArrowKey(event):
print('Got up arrow key press')
def onReturnKey(event):
print('Got return key press')
def onLeftClick(event):
print('Got left mouse button click:', end=' ')
showPosEvent(event)
def onRightClick(event):
print('Got right mouse button click:', end=' ')
showPosEvent(event)
def onMiddleClick(event):
print('Got middle mouse button click:', end=' ')
showPosEvent(event)
showAllEvent(event)
def onLeftDrag(event):
print('Got left mouse button drag:', end=' ')
showPosEvent(event)
def onDoubleLeftClick(event):
print('Got double left mouse click', end=' ')
showPosEvent(event)
tkroot.quit()
tkroot = Tk()
labelfont = ('courier', 20, 'bold') # family, size, style
widget = Label(tkroot, text='Hello bind world')
widget.config(bg='red', font=labelfont) # red background, large font
widget.config(height=5, width=20) # initial size: lines,chars
widget.pack(expand=YES, fill=BOTH)
widget.bind('', onLeftClick) # mouse button clicks
widget.bind('', onRightClick)
widget.bind('', onMiddleClick) # middle=both on some mice
widget.bind('', onDoubleLeftClick) # click left twice
widget.bind('', onLeftDrag) # click left and move
widget.bind('', onKeyPress) # all keyboard presses
widget.bind('', onArrowKey) # arrow button pressed
widget.bind('', onReturnKey) # return/enter key pressed
widget.focus() # or bind keypress to tkroot
tkroot.title('Click Me')
tkroot.mainloop()

Most of this file consists of
callback handler functions triggered when bound events
occur. As we learned in
Chapter 7
, this
type of callback receives an event object argument that gives details
about the event that fired. Technically, this argument is an instance of
the tkinter
Event
class, and its
details are attributes; most of the callbacks simply trace events by
displaying relevant event attributes.

When run, this script makes the window shown in
Figure 8-20
; it’s mostly intended just as
a surface for clicking and pressing event triggers.

Figure 8-20. A bind window for the clicking

The black-and-white medium of the book you’re holding won’t really
do justice to this script. When run live, it uses the configuration
options shown earlier to make the
window
show up as black on red, with a large
Courier font. You’ll have to take my word for it (or run this on your
own).

But the main point of this example is to demonstrate other kinds of
event binding protocols at work. We saw a script that intercepted left and
double-left mouse clicks with the widget
bind
method in
Chapter 7
, using event names

and

; the
script here demonstrates other kinds of events that are
commonly caught with
bind
:


To catch the press of a single key on the keyboard, register a
handler for the

event identifier; this is a lower-level way to input data in GUI
programs than the
Entry
widget
covered in the next section. The key pressed is returned in ASCII
string form in the event object passed to the callback handler
(
event.char
). Other attributes in
the event structure identify the key pressed in lower-level detail.
Key presses can be intercepted by the top-level root window widget
or by a widget that has been assigned keyboard focus with the
focus
method used by this
script.


This script also catches mouse motion while a button is held
down: the registered

event handler is called
every time the mouse is moved while the left button is pressed and
receives the current X/Y coordinates of the mouse pointer in its
event argument (
event.x
,
event.y
). Such information can be used to
implement object moves, drag-and-drop, pixel-level painting, and so
on (e.g., see the PyDraw examples in
Chapter 11
).


,

This script also catches right and middle mouse button clicks
(known as buttons 3 and 2). To make the middle button 2 click work
on a two-button mouse, try clicking both buttons at the same time;
if that doesn’t work, check your mouse setting in your properties
interface (the Control Panel on Windows).


,

To catch more specific kinds of key presses, this script
registers for the Return/Enter and up-arrow key press events; these
events would otherwise be routed to the general

handler and require event
analysis.

Here is what shows up in the
stdout
output stream after a left click, right
click, left click and drag, a few key presses, a Return and up-arrow
press, and a final double-left click to exit. When you press the left
mouse button and drag it around on the display, you’ll get lots of drag
event messages; one is printed for every move during the drag (and one
Python callback is run for each):

C:\...\PP4E\Gui\Tour>
python bind.py
Got left mouse button click: Widget=.25763696 X=376 Y=53
Got right mouse button click: Widget=.25763696 X=36 Y=60
Got left mouse button click: Widget=.25763696 X=144 Y=43
Got left mouse button drag: Widget=.25763696 X=144 Y=45
Got left mouse button drag: Widget=.25763696 X=144 Y=47
Got left mouse button drag: Widget=.25763696 X=145 Y=50
Got left mouse button drag: Widget=.25763696 X=146 Y=51
Got left mouse button drag: Widget=.25763696 X=149 Y=53
Got key press: s
Got key press: p
Got key press: a
Got key press: m
Got key press: 1
Got key press: -
Got key press: 2
Got key press: .
Got return key press
Got up arrow key press
Got left mouse button click: Widget=.25763696 X=300 Y=68
Got double left mouse click Widget=.25763696 X=300 Y=68

For mouse-related events, callbacks print the X and Y coordinates of
the mouse pointer, in the event object passed in. Coordinates are usually
measured in pixels from the upper-left corner (0,0), but are relative to
the widget being clicked. Here’s what is printed for a left, middle, and
double-left click. Notice that the middle-click callback dumps the entire
argument—all of the
Event
object’s
attributes (less internal names that begin with “__” which includes the
__doc__
string, and default operator
overloading methods inherited from the implied
object
superclass in Python 3.X). Different
event types set different event attributes; most key presses put something
in
char
, for instance:

C:\...\PP4E\Gui\Tour>
python bind.py
Got left mouse button click: Widget=.25632624 X=6 Y=6
Got middle mouse button click: Widget=.25632624 X=212 Y=95

char => ??
delta => 0
height => ??
keycode => ??
keysym => ??
keysym_num => ??
num => 2
send_event => False
serial => 17
state => 0
time => 549707945
type => 4
widget => .25632624
width => ??
x => 212
x_root => 311
y => 95
y_root => 221
Got left mouse button click: Widget=.25632624 X=400 Y=183
Got double left mouse click Widget=.25632624 X=400 Y=183
Other bind Events

Besides those illustrated in this example, a tkinter script can
register to catch additional kinds of bindable events. For
example:


  • fires
    when a button is released (

    is run when the button
    first goes down).


  • is triggered
    when a mouse pointer is moved.


  • and

    handlers intercept mouse
    entry and exit in a window’s display area (useful for automatically
    highlighting a widget).


  • is
    invoked when the window is resized, repositioned, and so on (e.g.,
    the event object’s
    width
    and
    height
    give the new window size).
    We’ll make use of this to resize the display on window resizes in
    the PyClock example of
    Chapter 11
    .


  • is invoked
    when the window widget is destroyed (and differs from the
    protocol
    mechanism for window manager
    close button presses). Since this interacts with widget
    quit
    and
    destroy
    methods, I’ll say more about the
    event later in this section.


  • and

    are run as the
    widget gains and loses focus.


  • and

    are run when a window is
    opened and iconified.


  • ,

    , and

    catch other special key
    presses.


  • ,

    , and

    catch other arrow key
    presses.

This is not a complete list, and event names can be written with a
somewhat sophisticated syntax of their own. For instance:

  • Modifiers
    can be added to event
    identifiers to make them even more specific; for instance,

    means moving the mouse
    with the left button pressed, and

    refers to pressing the
    “a” key only.

  • Synonyms
    can be used for some common
    event names; for instance,

    ,

    , and
    <1>
    mean a left mouse button press,
    and

    and

    mean the “a” key.
    All forms are case sensitive: use

    , not

    .

  • Virtual
    event identifiers can be defined
    within double bracket pairs (e.g.,
    <>
    ) to refer to a
    selection of one or more event sequences.

In the interest of space, though, we’ll defer to other Tk and
tkinter reference sources for an exhaustive list of details on this
front. Alternatively, changing some of the settings in the example
script and rerunning can help clarify some event behavior, too; this is
Python, after all.

More on events and the quit and destroy
methods

Before we move on, one event merits a few extra words: the

event (whose name
is case significant) is run when a widget is being destroyed, as a
result of both script method calls and window closures in general,
including those at program exit. If you bind this on a window, it will
be triggered once for each widget in the window; the callback’s event
argument
widget
attribute gives the
widget being destroyed, and you can check this to detect a particular
widget’s destruction. If you bind this on a specific widget instead,
it will be triggered once for that widget’s destruction only.

It’s important to know that a widget is in a “half dead” state
(Tk’s terminology) when this event is triggered—it still exists, but
most operations on it fail. Because of that, the

event is not intended for
GUI activity in general; for instance, checking a text widget’s
changed state or fetching its content in a

handler can both fail with
exceptions. In addition, this event’s handler cannot cancel the
destruction in general and resume the GUI; if you wish to intercept
and verify or suppress window closes when a user clicks on a window’s
X
button, use
WM_DELETE_WINDOW
in top-level windows’
protocol
methods as described
earlier in this chapter.

You should also know that running a tkinter widget’s
quit
method does not trigger any

events on exit, and even
leads to a fatal Python error on program exit in 3.X if any

event handlers are
registered. Because of this, programs that bind this event for non-GUI
window exit actions should usually call
destroy
instead of
quit
to close, and rely on the fact that a
program exits when the last remaining or only
Tk
root window (default or explicit) is
destroyed as described earlier. This precludes using
quit
for immediate shutdowns, though you can
still run
sys.exit
for brute-force
exits.

A script can also perform program exit actions in code run after
the
mainloop
call returns, but the
GUI is gone completely at this point, and this code is not associated
with any particular widget. Watch for more on this event when we study
the PyEdit example program in
Chapter 11
; at the risk of spoiling the end of
this story, we’ll find it unusable for verifying changed text
saves.

BOOK: Programming Python
2.71Mb size Format: txt, pdf, ePub
ads

Other books

Killing the Dead by Richard Murray, Richard Murray
A Vein of Deceit by Susanna Gregory
Sue-Ellen Welfonder - [MacLean 03] by Wedding for a Knight
Witch Twins at Camp Bliss by Adele Griffin
Close Encounters by Katherine Allred
The Radiant City by Lauren B. Davis