MIME-Version: 1.0 Content-Location: file:///C:/90861A52/Week12.htm Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset="us-ascii"
Week =
12
GUI Programming
Computer Science A202 /
A598
and Informatics I211
Basic=
GUI
Elements
<= ![if !supportLists]>n There are three basic Graphic User Interface (GUI) elements<= o:p>
<=
![if !supportLists]>q <=
/span>widgets that =
are
visible on the screen
<=
![if !supportLists]>n &nb=
sp; examples: buttons, labels, check boxes, text fields, and scroll bars=
<=
![if !supportLists]>q
a layout manager
that determines where the widgets are positioned on the screen
<=
![if !supportLists]>q <=
/span>event handler funct=
ions
that are invoked when GUI events occur
<=
![if !supportLists]>n &nb=
sp; examples:
<=
![if !supportLists]>q =
span>left mouse button click on a GUI button
<=
![if !supportLists]>q =
span><enter> key pressed with focus on a text field
<=
![if !supportLists]>q =
span>scroll bar moved
Pytho=
n's Tkinter
module
<=
![if !supportLists]>n =
span>Most programming languages have several libraries =
for
GUI programming
<=
![if !supportLists]>q
for example in Java the=
two
most popular libraries are in the packages java.awt and javax.swi=
ng
<=
![if !supportLists]>q <=
/span>generally you must use just one GUI library in a program
<=
![if !supportLists]>q <=
/span>the widget, layout manager, and handler concepts are similar regardl=
ess
of the GUI library
<=
![if !supportLists]>n =
span>The module Tkinter contains Python's most
widely used and most portable GUI library
<=
![if !supportLists]>q <=
/span>"Tkinter" stands for "Tk interface"
<=
![if !supportLists]>q <=
/span>note the capital T
<=
![if !supportLists]>q <=
/span>Tk is a popular GUI Tool kit
(library) developed in Unix systems and ported to most other systems
<=
![if !supportLists]>q
the IDLE interface uses=
Tkinter
<=
![if !supportLists]>n =
span>See the course web resources page for links to =
Tkinter
documentation (which isn't as good as most other Python docs)
click GUI example
# click.py by
from Tkinter import * # import everything from Tkinter module
root =3D Tk() # create a Tk interpreter with frame
label =3D Label(root, text=3D'Hello, Tk user!') # create a label wid=
get
label.grid() # display it in the root frame with the grid layout man=
ager
def clickHandler(): # installed to handle button clicks
label.con=
fig(text=3D'You
clicked') # change the label text
# create a button with click handler and display it
Button(root, text=3D'Click me', command=3DclickHandler).grid()
mainloop() # listen for events, don't end application
Overa=
ll
form for a Tkinter program application
from Tkinter import *
<=
![if !supportLists]>q =
import everything from the Tkinter module
<=
![if !supportLists]>q =
note the capital T
root =3D Tk()
<=
![if !supportLists]>q =
create an instance of the class Tk, which create a Tk interpr=
eter
and a new frame (window) on the display
<=
![if !supportLists]>q =
root is the parent of all G=
UI
widgets
<=
![if !supportLists]>n =
unless nested containers are used, as explained later
<=
![if !supportLists]>q =
only do this once in an application: if you need other frames, use a
different class
<=
![if !supportLists]>n &nb=
sp;
Application-specific co=
de
here …
<=
![if !supportLists]>q =
for example defining event handlers, creating widgets, informing the
layout manager of the widgets, and installing the event handlers
mainloop()
<=
![if !supportLists]>q =
tells the Tk interpreter to listen for GUI events
<=
![if !supportLists]>q =
this call does not return until the GUI is terminated, so it must be
executed after all other GUI setup code
<=
![if !supportLists]>q =
without this statement the application will terminate immediately
Steps=
for
building a basic GUI, part 1
<=
![if !supportLists]>n These
steps may be done in any order or interleaved, so long as values are defined
before they are used
<=
![if !supportLists]>q <=
/span>of course try to organize the code in way that aids
understanding
<=
![if !supportLists]>n Define
event handlers
<=
![if !supportLists]>q <=
/span>unlike other code you write, event handlers are ca=
lled
automatically by the system, not by your program code
<=
![if !supportLists]>q <=
/span>event handlers are also called listeners,
because they are called when some event is "heard"
<=
![if !supportLists]>q <=
/span>for example, the button handler in the click
example
def clickHandle=
r():
label.config(text=3D'You clicked')
Steps=
for
building a basic GUI, part 2
<=
![if !supportLists]>n =
span>Create widgets
<=
![if !supportLists]>q <=
/span>each is an instance of a class
<=
![if !supportLists]>q <=
/span>each has a parent contains it (for now always root)
<=
![if !supportLists]>q <=
/span>in the click example
label =3D Label=
(root,
text=3D'Hello, Tk user!')
Button(root,
text=3D'Click me', command=3DclickHandler).grid()
<=
![if !supportLists]>n =
span>Inform the layout manager of each widget
<=
![if !supportLists]>q <=
/span>often information on how to position a widget is provided at this ti=
me
<=
![if !supportLists]>q <=
/span>in the click example, which uses the grid layout manag=
er,
there is the grid() method call to the anonymous Button widget
above and the call label.grid()
<=
![if !supportLists]>n =
span>Install a handler in each widget that has an event=
of
interest
<=
![if !supportLists]>q <=
/span>as above with the command parameter of the Button widg=
et
A sec=
ond
example: upCounter
# upCounter.py by
from Tkinter import *
root =3D Tk()
count =3D 0
label =3D Label(root, text=3Dstr(count))
label.grid()
def clickHandler():
global co=
unt #
required for local assignment
count +=
=3D 1
label.con=
fig(text=3Dstr(count))
Button(root, text=3D'Increment', command=3DclickHandler).grid()
mainloop()
Widget
attributes
<=
![if !supportLists]>n Widgets
have configuration attributes that may be set when the widgets are
created
<=
![if !supportLists]>q <=
/span>they all have default values if not specified
<=
![if !supportLists]>q <=
/span>in the upCounter example text and command
attributes are set when the label and button widgets are created
label =3D Label(root, text=3Dstr(count))
Button(root, text=3D'Increment', command=3DclickHandler).grid()
<=
![if !supportLists]>n A
widget's attribute values can also be changed at any time using its .con=
fig
method
<=
![if !supportLists]>q <=
/span>event handlers frequently do this
<=
![if !supportLists]>q <=
/span>for example, in the clickHandler function of
the upCounter example
label.config(text=3Dstr(count))
downCounter description
<=
![if !supportLists]>n We
create a downCounter GUI frame uses three widgets <=
![if !supportLists]>q a label displaying the count <=
![if !supportLists]>q a button that decrements the count <=
![if !supportLists]>q an entry widget in which a new count value =
can
be entered downCounter
implementation from Tkinter import * root =3D Tk() count =3D 0 def clickHandler(): global co=
unt count -=
=3D 1
label.config(text=3Dstr(count)) def entryHandler(_): global co=
unt count =3D
int(entry.get())
label.config(text=3Dstr(count)) label =3D Label(root, text=3Dstr(count)) label.grid() Button(root, text=3D'Decrement', command=3DclickHandler).grid() entry =3D Entry(root, width=3D6) entry.bind('<Return>', entryHandler) # install event hander for
keyboard return entry.grid() mainloop() Entry
widgets <=
![if !supportLists]>n An
Entry widget is a one-line box for entering text <=
![if !supportLists]>q <=
/span>in other GUI tool kits such widgets are often call=
ed
"text fields" <=
![if !supportLists]>n A width
attribute specifies the box width in characters <=
![if !supportLists]>n An
entry has the keyboard focus if there is a vertical cursor in it <=
![if !supportLists]>q <=
/span>the user can move the focus to an entry by clickin=
g in
it <=
![if !supportLists]>q <=
/span>a widget only responds to keyboard events if it has
the focus <=
![if !supportLists]>n A
call of the form entry.bind('<Return>', handler<=
b>) installs
the handler function to handle the event of a keyboard return if =
entry
has the focus <=
![if !supportLists]>q <=
/span>handlers installed by the .bind method take=
one
argument, which in this use can be ignored <=
![if !supportLists]>q <=
/span>we have seen that handlers installed as command=
attributes take no arguments Layout
managers <=
![if !supportLists]>n A
widget cannot be displayed until the layout manager is informed of its
existence and given any needed information on how it is to be positioned <=
![if !supportLists]>n Tkinter
has three layout managers <=
![if !supportLists]>q <=
/span>grid layou=
t is
not complicated and is fairly powerful <=
![if !supportLists]>n &nb=
sp; it is the only one we will use <=
![if !supportLists]>q <=
/span>pack layou=
t is
very powerful, but harder to understand <=
![if !supportLists]>q
place<=
span
style=3D'font-size:10.0pt;font-family:Arial;mso-bidi-font-family:Arial;
mso-bidi-language:#AC45'> layout allows the program to control just where
widgets go
<=
![if !supportLists]>q <=
/span>never use =
more
than one layout manager (in the same container)
<=
![if !supportLists]>q <=
/span>most GUI libraries have grid and place layout mana=
gers
of some kind, though they differ widely in the details of their operation
<=
![if !supportLists]>n&nb=
sp;
Tkinter layout managers redo t=
he
layout whenever a widget is added or modified
Grid
layout
<=
![if !supportLists]>n Grid
layout arranges widgets in a table-like format with rows and columns
<=
![if !supportLists]>q <=
/span>it is similar to the table layout in HTML,
spreadsheets , and text editors (such as Word)
<=
![if !supportLists]>n The
width of each column is determined by the width of the widest widget in the
column
<=
![if !supportLists]>q <=
/span>similarly row height is based on the maximum eleme=
nt
height
<=
![if !supportLists]>n Normally
the grid cell in which a widget is placed is specified in its .grid
method call by keyword arguments
<=
![if !supportLists]>q <=
/span>widget.grid=
(row=3DrowIndex, col=
umn=3DcolumnIndex)
<=
![if !supportLists]>q <=
/span>zero-based indexing
<=
![if !supportLists]>q <=
/span>if neither is specified, as in the .grid()
calls in our examples so far, the widget is placed in column 0 of a new row=
at
the bottom
Advan=
ced
grid layout, part 1
<=
![if !supportLists]>n =
span>In your project you are not expected to use this a=
nd
other "advanced" features in these notes, but you are encouraged =
to
try them if you like
<=
![if !supportLists]>n =
span>The sticky option (keyword argument) gives
control over where the widget is positioned in a grid cell if it does not f=
ill
the whole cell
<=
![if !supportLists]>q <=
/span>values for this option are the Tkinter constants N, S, E, =
W,
NW, NE, SW, and SE, making the widget be as close as possible to=
the
edge or corner of the grid cell in the indicated direction
<=
![if !supportLists]>n &nb=
sp; example: label.grid(row=3D0, column=3D0, sticky=3DE) will rig=
ht-justify
label in the upper-left cell
<=
![if !supportLists]>q <=
/span>these constants may be added to stretch the widget
<=
![if !supportLists]>n &nb=
sp; example: E+W stretches the widget to fill the cell horizontal=
ly
<=
![if !supportLists]>q <=
/span>the default position is centered in the cell
<=
![if !supportLists]>n =
span>The columnspan option indicates that the wi=
dget
is to be layed out in an area that spans the indicated number of columns
<=
![if !supportLists]>q <=
/span>example: label.grid(row=3D0, column=3D1, columnspan=3D2) will=
position label
in the area of the 2nd and 3rd columns of row 1
<=
![if !supportLists]>q <=
/span>similar to columnspan specifications in HTML tables and spreadsheets=
Advan=
ced
grid layout, part 2
<=
![if !supportLists]>n The
.columnconfigure (or .rowconfigure) method of a parent (e.g. =
root)
may be used to options that apply to an entire row or column
<=
![if !supportLists]>q <=
/span>the first argument is the column (or row) index
<=
![if !supportLists]>q <=
/span>the minsize options specifies the minimum w=
idth
(or height) of the column (row) in pixels
<=
![if !supportLists]>q <=
/span>the pad option specifies extra space to be
added to the width (or height) in pixels
<=
![if !supportLists]>q <=
/span>example: root.columnconfigure(1, pad=3D5) a=
dds 5
pixels of width to the second column
<=
![if !supportLists]>n There
are many more GUI features, including more grid layout possibilities,
that you can explore in the Tkinter documentation. GUIs can be
complicated!
resetCounter description
<=
![if !supportLists]>n The
resetCounter GUI frame has three rows and two columns
<=
![if !supportLists]>n The
first row has a Decrement counter descriptive label that does not ch=
ange
and spans both columns
<=
![if !supportLists]>n The
second row has a Reset button in the first column and an entry for a
reset value in the second column
<=
![if !supportLists]>n The
third row has a Decrement button in the first column and a label
displaying the count value in the second column
<=
![if !supportLists]>q no decrement occurs if the counter has reached zer=
o
<=
![if !supportLists]>q the initial counter and reset values are zero
resetCounter implementation, part 1
from Tkinter import *
root =3D Tk()
count =3D 0
resetValue =3D 0
def decrementHandler():
global co=
unt #
required for local assignment of global variables
if count =
>
0:
count -=3D 1
showCount()
def showCount(): label.config(text=3Dstr(count))
def resetHandler():
global co=
unt;
count =3D resetValue
showCount=
()
def entryHandler(_):
global re=
setValue
resetValu=
e =3D
int(entry.get())
entry.del=
ete(0,
END)
resetHand=
ler()
resetCounter implementation, part 2
Label(root, text=3D'Decrement counter').grid(row=3D0, column=3D0,
columnspan=3D2)
root.columnconfigure(0, pad=3D10)
Button(root, text=3D'Reset', command=3DresetHandler).grid(row=3D1, c=
olumn=3D0,
=
&nb=
sp; =
&nb=
sp;
sticky=3DW)
entry =3D Entry(root, width=3D4)
entry.bind('<Return>', entryHandler) # event hander for keyboa=
rd
return
entry.grid(row=3D1, column=3D1)
Button(root, text=3D'Decrement', command=3DdecrementHandler).grid(ro=
w=3D2,
=
&nb=
sp; =
&nb=
sp;
column=3D0,
=
&nb=
sp; =
&nb=
sp; =
sticky=3DW)
label =3D Label(root, text=3Dstr(count))
label.grid(row=3D2, column=3D1, sticky=3DW)
mainloop()
timer description
<=
![if !supportLists]>n The
timer application plays a sound when a given number of seconds has
elapsed and is easily reset to time the same interval again
<=
![if !supportLists]>n Its
GUI has
<= ![if !supportLists]>q <= /span>a text entry box for entering a number of seconds<= o:p>
<=
![if !supportLists]>q <=
/span>a Start button for starting the timer
<=
![if !supportLists]>q <=
/span>a label indicating how many seconds are left
timer implementation
from Tkinter import *
import winsound, threading
root =3D Tk()
tickInterval =3D 1 # seconds
=
timer =3D None
<=
![if !supportLists]>q
function definiti=
ons
here
label =3D Label(root, text=3D'')
label.grid()
entry =3D Entry(root, width=3D6)
entry.bind('<Return>', entryHandler) # install event hander for
keyboard return
entry.grid()
entry.focus() # start with focus on text entry
button =3D Button(root, text=3D'Start', command=3DstartHandler)
button.grid()
button.bind('<Return>', entryHandler)
mainloop()
timer function definitions, part 1
def setSeconds(secs):
global se=
conds
seconds =
=3D secs
label.config(text=3Dstr(seconds))
def startTimer(secs):
global ti=
mer
setSecond=
s(secs)
# invoke
timerCallback after tickInterval seconds
timer =3D
threading.Timer(tickInterval, timerCallback)
timer.sta=
rt()
def timerCallback():
if second=
s >
1:
startTimer(seconds - tickInterval)
else:
done()
timer function definitions, part 2
def timerCallback():
if second=
s >
1:
startTimer(seconds - tickInterval)
else:
done()
def done():
label.config(text=3D'Done')
winsound.PlaySound('play default beep', winsound.SND_FILENAME)
button.fo=
cus()
# with focus on button, <return> will restart timer
def entryHandler(ignored):
startHand=
ler()
def startHandler():
global se=
conds
try:
startTimer(int(entry.get()))
except: #=
clear
the entry text if it is bogus
entry.delete(0, len(entry.get()))
Advan=
ced
layout: containers
<=
![if !supportLists]>n =
span>In our examples so far, the layout has consisted
entirely of widgets
<=
![if !supportLists]>n =
span>More generally, layout managers position compon=
ents
that may be either widgets or containers containing other components=
<=
![if !supportLists]>n =
span>Each container is drawn on in a rectangular area w=
ith
width, height, and position (like a widget), and also has its own layout
manager for its components
<=
![if !supportLists]>n =
span>The screen may thus be viewed as a collection on
non-overlapping, but possibly nested, rectangles
<=
![if !supportLists]>q <=
/span>those rectangles containing others are containers <=
![if !supportLists]>q <=
/span>this nesting ability allows much greater layout freedom <=
![if !supportLists]>n =
span>This use of components, containers, and widgets is=
the
same in most GUI libraries Advan=
ced:
frames are Tkinter containers <=
![if !supportLists]>n In
Tkinter, instances of the Frame class are containers <=
![if !supportLists]>n Instances
of the Tk class are frames <=
![if !supportLists]>q <=
/span>for example root in our code <=
![if !supportLists]>n The
first argument of every widget constructor is the container in which it is
nested (layed out) <=
![if !supportLists]>q <=
/span>this has been root in our code so far <=
![if !supportLists]>n Create
all the components within a container before making the container's layout
manager call <=
![if !supportLists]>n Frames
have specified width and height attributes, allowing empty frames (containi=
ng
no components) to be used to add blank space in the layout of their parent
container Advan=
ced
frame example <=
![if !supportLists]>n
frameCounter.py is derived from <=
b>resetCounter.py <=
![if !supportLists]>q <=
/span>difference: the entry box is located 10 pixels to the right of the r=
eset
button using a containing frame with groove relief and an empty space frame=
<=
![if !supportLists]>q <=
/span>in resetCounter.py, replace the reset button and entry lines =
with
the following frame =3D Frame(root, borderwidth=3D2, relief=3DGROOVE) Button(frame, text=3D'Reset', command=3DresetHandler).grid(row=3D0, =
=
&nb=
sp; =
&nb=
sp;
column=3D0) Frame(frame, width=3D10).grid(row=3D0, column=3D1) # add 10 pixels o=
f space entry =3D Entry(frame, width=3D4) entry.bind('<Return>', entryHandler) entry.grid(row=3D0, column=3D2) entry.focus() # start with focus on text entry # must be after creating reset button, space frame, and entry widget=
s frame.grid(row=3D1, column=3D0, columnspan=3D2, sticky=3DW)=
b> Advan=
ced:
timer and dialogTimer examples <=
![if !supportLists]>n timer.py is a handly
application that beeps and says "Done" after a given number of
seconds <=
![if !supportLists]>q <=
/span>this illustrates the use of the threading.Timer=
class with a callback function invoked when the time has elapsed <=
![if !supportLists]>n dialogTimer.py is a =
fancy
version of timer.py <=
![if !supportLists]>q <=
/span>among other new functionality, it pops up a dialog
frame when the time has elapsed <=
![if !supportLists]>q <=
/span>among other new programming tricks, it uses <=
![if !supportLists]>n &nb=
sp; .geometry to control the positio=
n of
a window on the screen <=
![if !supportLists]>n &nb=
sp; tkFont.Font to create a large font <=
![if !supportLists]>n &nb=
sp; the background attribute to set color <=
![if !supportLists]>n &nb=
sp; a handy function to manage optional command arguments <=
![if !supportLists]>n &nb=
sp; the <Escape> binding to allow closing of a dialog with =
the
escape key
# click.py by chaynes@indiana.edu
from Tkinter import * # import everything, note capital T
root =3D Tk() # create a Tk interpreter with frame
label =3D Label(root, text=3D'Hello, Tk user!') # create a label widget
label.grid() # display it in the root frame with the grid layout manager
def clickHandler(): # installed to handle button clicks
label.config(text=3D'You clicked') # change the label text
# create a button with click handler and display it
Button(root, text=3D'Click me', command=3DclickHandler).grid()
mainloop() # listen for events, don't end application
'''dialogTimer.py by chaynes@indiana.edu
Usage: python dialogTimer.py [TIME [TICK_INTERVAL [TICK_DECREMENT]]]
Display a window with an entry box, start button, and time label. Entering a number
or pressing start begins a countdown from TIME by TICK_DECREMENT every TICK_INTERVAL
seconds (defaults 10, 6, and .1, resp.). The time is self-starting if the time is
not 0. The timer may be started or restarted by entering a time in the box, which
becomes the new time, or pressing start, which starts the count from the time in the
box.
When the time reaches zero (or very close to it), the displayed time changes to
'Done', beeps, and displays a dialog saying "Time's up!" and presenting a button with
the focus that restarts the timer from its last entry value. Restarting the timer,
either by this button or the main timer window entry box or button dismisses the
dialog.
'''
from Tkinter import *
import winsound, threading, sys, tkFont
root =3D Tk()
root.title('Timer')
def nextArg(default):
if len(sys.argv) > 1:
return sys.argv.pop(1)
else:
return default
time =3D float(nextArg(10)) # initial time value
tickInterval =3D float(nextArg(6)) # seconds
tickDecrement =3D float(nextArg(.1))
timer =3D None
dialog =3D None # time over dialog frame
def setTime(t):
global time
time =3D t
label.config(text=3D'%.1f'%time)
def startTimer(time):
global timer
setTime(time)
# invoke timerCallback after tickInterval seconds
timer =3D threading.Timer(tickInterval, timerCallback)
timer.start()
def timerCallback():
if time > tickDecrement + .0001:
startTimer(time - tickDecrement)
else:
done()
def done():
label.config(text=3D'Done')
winsound.PlaySound('play default beep', winsound.SND_FILENAME)
button.focus() # with focus on button, <return> will start timer again
global dialog
dialog =3D Toplevel(root)
labelFont =3D tkFont.Font(family=3D'Ariel', size=3D18)
Label(dialog, text=3D"Time's up!", font=3DlabelFont, background=3D'red').grid()
restart =3D Button(dialog, text=3D'Restart', command=3DstartHandler)
restart.grid(row=3D0, column=3D1, padx=3D5)
restart.bind('<Return>', startHandler)
restart.focus()
restart.bind_all('<Escape>', closeHandler)
dialog.geometry('170x30+400+300') # format WIDTHxHEIGHT+X+Y
def closeHandler(*args): # take zero or one argument
global dialog
dialog.destroy()
dialog =3D None
def startHandler(*args):
if dialog: # if there is a dialog, kill it
closeHandler()
try:
startTimer(float(entry.get()))
except: # clear the entry text if it is bogus
entry.delete(0, len(entry.get()))
entry =3D Entry(root, width=3D4)
entry.bind('<Return>', startHandler) # install event hander for keyboard return
entry.grid(row=3D0, column=3D0)
entry.insert(0, str(time)) # instert time in entry box
entry.select_range(0, END) # select all text in entry box
entry.focus() # start with focus on text entry
button =3D Button(root, text=3D'Start', command=3DstartHandler)
button.grid(row=3D0, column=3D1)
button.bind('<Return>', startHandler)
root.columnconfigure(2, minsize=3D50)
label =3D Label(root, padx=3D3)
label.grid(row=3D0, column=3D2)
root.geometry('1x25+10+10')
if time !=3D 0:
startHandler()
mainloop()
# downCounter.py by chaynes@indiana.edu
from Tkinter import *
root =3D Tk()
count =3D 0
label =3D Label(root, text=3Dstr(count))
label.grid()
def clickHandler():
global count # required for local assignment of global variables
count -=3D 1
showCount()
def showCount():
label.config(text=3Dstr(count))
def entryHandler(_):
global count
count =3D int(entry.get())
showCount()
Button(root, text=3D'Decrement', command=3DclickHandler).grid()
entry =3D Entry(root, width=3D6)
entry.bind('<Return>', entryHandler) # install event hander for keyboard return
entry.grid()
mainloop()
# frameCounter.py by chaynes@indiana.edu
from Tkinter import *
root =3D Tk()
count =3D 0
resetValue =3D 0
def decrementHandler():
global count # required for local assignment of global variables
if count > 0:
count -=3D 1
showCount()
def showCount():
label.config(text=3Dstr(count))
def resetHandler():
global count; count =3D resetValue
showCount()
def entryHandler(_):
global resetValue
resetValue =3D int(entry.get())
entry.delete(0, END)
resetHandler()
Label(root, text=3D'Decrement counter').grid(row=3D0, column=3D0, columnspan=3D2)
root.columnconfigure(0, pad=3D10)
frame =3D Frame(root, borderwidth=3D2, relief=3DGROOVE)
Button(frame, text=3D'Reset', command=3DresetHandler).grid(row=3D0, column=3D0)
Frame(frame, width=3D10, borderwidth=3D2, relief=3DGROOVE).grid(row=3D0, column=3D1) # add 10 pixels of space
entry =3D Entry(frame, width=3D4)
entry.bind('<Return>', entryHandler) # install event hander for keyboard return
entry.grid(row=3D0, column=3D2)
# must be after creating the reset button, space frame, and entry
frame.grid(row=3D1, column=3D0, columnspan=3D2, sticky=3DW)
Button(root, text=3D'Decrement', command=3DdecrementHandler).grid(row=3D2, column=3D0,
sticky=3DW)
label =3D Label(root, text=3Dstr(count))
label.grid(row=3D2, column=3D1, sticky=3DW)
mainloop()
# resetCounter.py by chaynes@indiana.edu
from Tkinter import *
root =3D Tk()
count =3D 0
resetValue =3D 0
def decrementHandler():
global count # required for local assignment of global variables
if count > 0:
count -=3D 1
showCount()
def showCount():
label.config(text=3Dstr(count))
def resetHandler():
global count; count =3D resetValue
showCount()
def entryHandler(_):
global resetValue
resetValue =3D int(entry.get())
entry.delete(0, END)
resetHandler()
Label(root, text=3D'Decrement counter').grid(row=3D0, column=3D0, columnspan=3D2)
root.columnconfigure(0, pad=3D10)
Button(root, text=3D'Reset', command=3DresetHandler).grid(row=3D1, column=3D0, sticky=3DW)
entry =3D Entry(root, width=3D4)
entry.bind('<Return>', entryHandler) # install event hander for keyboard return
entry.grid(row=3D1, column=3D1)
Button(root, text=3D'Decrement', command=3DdecrementHandler).grid(row=3D2, column=3D0,
sticky=3DW)
label =3D Label(root, text=3Dstr(count))
label.grid(row=3D2, column=3D1, sticky=3DW)
mainloop()
# timer.py by chaynes@indiana.edu
from Tkinter import *
import winsound, threading
root =3D Tk()
tickInterval =3D 1 # seconds
time =3D 0
timer =3D None
def setTime(t):
global time
time =3D t
label.config(text=3Dstr(time))
def startTimer(secs):
global timer
setTime(secs)
# invoke timerCallback after tickInterval seconds
timer =3D threading.Timer(tickInterval, timerCallback)
timer.start()
def timerCallback():
if time > 1:
startTimer(time - tickInterval)
else:
done()
def done():
label.config(text=3D'Done')
winsound.PlaySound('play default beep', winsound.SND_FILENAME)
button.focus() # with focus on button, <Return> will start timer again
def startHandler(*args): # take zero or one argument
global time
try:
startTimer(int(entry.get()))
except: # clear the entry text if it is bogus
entry.delete(0, len(entry.get()))
label =3D Label(root)
label.grid()
entry =3D Entry(root, width=3D6)
entry.bind('<Return>', startHandler) # install event hander for keyboard return
entry.grid()
entry.focus() # start with focus on text entry
button =3D Button(root, text=3D'Start', command=3DstartHandler)
button.grid()
button.bind('<Return>', startHandler)
mainloop()
# upCounter.py by chaynes@indiana.edu
from Tkinter import *
root =3D Tk()
count =3D 0
label =3D Label(root, text=3Dstr(count))
label.grid()
def clickHandler():
global count # required for local assignment of global variables
count +=3D 1
label.config(text=3Dstr(count))
Button(root, text=3D'Increment', command=3DclickHandler).grid()
mainloop()