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 9-15 illustrates more
bind
event protocols.
Example 9-15. PP3EGuiTourind.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): 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:', showPosEvent(event) def onRightClick(event): print 'Got right mouse button click:', showPosEvent(event) def onMiddleClick(event): print 'Got middle mouse button click:', showPosEvent(event) showAllEvent(event) def onLeftDrag(event): print 'Got left mouse button drag:', showPosEvent(event) def onDoubleLeftClick(event): print 'Got double left mouse click', 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('<Button-1>', onLeftClick) # mouse button clicks widget.bind('<Button-3>', onRightClick) widget.bind('<Button-2>', onMiddleClick) # middle=both on some mice widget.bind('<Double-1>', onDoubleLeftClick) # click left twice widget.bind('<B1-Motion>', onLeftDrag) # click left and move widget.bind('<KeyPress>', onKeyPress) # all keyboard presses widget.bind('<Up>', onArrowKey) # arrow button pressed widget.bind('<Return>', 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 8, these callbacks receive 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 9-20; it’s mostly intended just as a surface for clicking and pressing event triggers.
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 earlier; the script here
demonstrates other kinds of events that are commonly caught with
bind
:
<KeyPress>
To catch the press of a single key on the keyboard,
register a handler for the <KeyPress>
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 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.
<B1-Motion>
This script also catches mouse motion while a button is
held down: the registered <B1-Motion>
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 12).
<Button-3>
,
<Button-2>
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).
<Return>
, <Up>
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 <KeyPress>
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:...PP3EGuiTour>python bind.py
Got left mouse button click: Widget=.7871632 X=209 Y=79
Got right mouse button click: Widget=.7871632 X=209 Y=79
Got left mouse button click: Widget=.7871632 X=83 Y=63
Got left mouse button drag: Widget=.7871632 X=83 Y=65
Got left mouse button drag: Widget=.7871632 X=84 Y=66
Got left mouse button drag: Widget=.7871632 X=85 Y=66
Got left mouse button drag: Widget=.7871632 X=85 Y=67
Got left mouse button drag: Widget=.7871632 X=85 Y=68
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=.7871632 X=85 Y=68
Got double left mouse click Widget=.7871632 X=85 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. Different event
types set different event attributes; most key presses put something
in char
, for instance:
C:...PP3EGuiTour>python bind.py
Got left mouse button click: Widget=.7871632 X=163 Y=18
Got middle mouse button click: Widget=.7871632 X=152 Y=110
<Tkinter.Event instance at 7b3640>
char => ??
height => 0
keycode => 2
keysym => ??
keysym_num => 2
num => 2
send_event => 0
serial => 14
state => 0
time => 5726238
type => 4
widget => .7871632
width => 0
x => 152
x_root => 156
y => 110
y_root => 133
Got left mouse button click: Widget=.7871632 X=152 Y=110
Got double left mouse click Widget=.7871632 X=152 Y=110
Besides the ones illustrated in this example, a Tkinter script can register to catch additional kinds of bindable events. For example:
<ButtonRelease>
fires when a button is released (<ButtonPress>
is run when the
button first goes down).
<Motion>
is
triggered when a mouse pointer is moved.
<Enter>
and
<Leave>
handlers
intercept mouse entry and exit in a window’s display area (useful
for automatically highlighting a widget).
<Configure>
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).
<Destroy>
is
invoked when the window widget is destroyed (and differs from the
protocol
mechanism for window
manager close button presses).
<FocusIn>
and
<FocusOut>
are run as the
widget gains and loses focus.
<Map>
and <Unmap>
are run when a window is
opened and iconified.
<Escape>
, <BackSpace>
, and <Tab>
catch other special key
presses.
<Down>
, <Left>
, and <Right>
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 example:
Modifiers can be added to event
identifiers to make them even more specific; for instance,
<B1-Motion>
means moving
the mouse with the left button pressed, and <KeyPress-a>
refers to pressing
the “a” key only.
Synonyms can be used for some common
event names; for instance, <ButtonPress-1>
, <Button-1>
, and <1>
mean a left mouse button
press, and <KeyPress-a>
and <Key-a>
mean the “a”
key. All forms are case sensitive: use <Key-Escape>
, not <KEY-ESCAPE>
.
Virtual event identifiers can be
defined within double bracket pairs (e.g., <<PasteText>>
) 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.
3.139.240.119