What makes Python good at GUIs?
¨ Rapid turnaround… easy to experiment
¨ Very high-level… fast to code GUIs
¨ Object-oriented… code reusability
¨ Dynamic reloading… changes without stopping
¨ Tkinter
·
Python’s OO interface to the portable Tk
· Part of Python, lightweight, well documented, robust
· Meshes well with a scripting language: from Tcl
· Runs with native look-and-feel on X, MS-Windows, Macs
· Structure: Tkinter + Tk lib + (X, Windows, Mac libs)
· A de-facto standard: Tk used by Python, Perl, and TCL
· An open source system, supported by Scriptics
·
Base
¨ wxPython
·
Second most popular GUI
· Portable GUI class library written in C++ (X, Windows, Mac)
·
Wraps a C++
· Rich widget set: trees, html viewers, notebooks
·
Tends to be more complex: C++
· Was less documented, but wxPython book in 2006
· GUI builders: BoaConstructor, wxDesigner
· Tkinter + PMW package roughly as rich as wxPython
¨ PyQt, PyGTK
·
From
·
PyQt third most popular GUI
· PyQt: works on Sharp Zaurus PDAs, open source book
· PyQt: not completely open source (still true?)
· Qt GUI builders: BlackAdder, QT Designer
¨ PyWin32 (former known as win32all)
·
¨ Jython (a.k.a. Jpython)
· Access to Java GUI APIs: AWT, Swing, etc.
¨ IronPython
.
·
.
¨ PythonCard
·
¨ Dabo
· 3-tier application builder with GUI, Dbase, logic
¨ Anygui
·
Portable
See: Extras\Gui\wxPython\wxPython.doc
on CD for Tkinter, wxPython comparisons
¨ Widgets: class instances
¨ Options: keyword arguments
¨ Tkinter exports classes and
constants
¨ Widgets must be packed (or gridded,
placed)
¨ ‘mainloop’ shows widgets, catches
events
file: gui1.py
from Tkinter import * # get widget classes
Label(text="Hello GUI world!").pack() # make a label
mainloop() # show, catch events
% python gui1.py
¨ Frames are widget containers
¨ Widgets attach to sides of a parent
¨ Event handlers are any callable object
¨ Button handlers are registered as ‘command’ options
file: gui2.py
from Tkinter import * # get widgets
def callback(): # define handler
print 'hello stdout world...'
top = Frame() # make a container
top.pack()
Label(top, text="Hello callback world").pack(side=TOP)
Button(top, text="press me",
command=callback).pack(side=BOTTOM)
top.mainloop()
% python gui2.py
hello stdout world...
hello stdout world...
Example: a live GUI demo
¨ Entry is a one-line input field
¨ lambda defers call to add an input argument
¨ showinfo is one of a set of common dialog calls
¨ Tk main window & Toplevel popups have icon, title
¨ + multi-line text, menus, radio/check buttons, dialogs,…
file: gui3.py
from Tkinter import *
from tkMessageBox import showinfo
def reply(name):
showinfo(title='Reply', message='Hello %s!' % name)
top = Tk()
top.title('Echo')
top.iconbitmap('py-blue-trans-out.ico')
Label(top, text="Enter your name:").pack(side=TOP)
ent = Entry(top)
ent.pack(side=TOP)
btn = Button(top, text="Submit",
command=(lambda: reply(ent.get())))
btn.pack(side=LEFT)
top.mainloop()
Other event interfaces
· widget.bind(“<B1-Motion>”, func) [CD bind.py]
· widget.after(msecs, func)
· slider/widget linkage, data stream conditions
GUI construction
· “What you build is what you get”
· Layout = build order + pack options
· Each Toplevel instance is a window
· Default Toplevel window if no parent
· Widgets nest in Frames, Frames nest in other Frames
· Object trees: Tkinter cross-links parents to children
“Decreasing Cavity Model”
· pack gives widget entire side
· widgets packed later get side of what’s left
· grid, place: alternative geometry managers
Widget packing Þ
Ü Widget tree
¨ Organization framework: namespace, inheritance
¨ Methods attach widgets to ‘self’
¨ Callbacks are bound methods of ‘self’
file: hello.py
#!/usr/local/bin/python
from Tkinter import * # get widgets
class Hello(Frame): # container subclass
def __init__(self, parent=None):
Frame.__init__(self, parent) # superclass init
self.pack()
self.make_widgets() # attach to self
def make_widgets(self):
widget = Button(self, text='Hello',
command=self.onPress)
widget.pack(side=LEFT)
def onPress(self):
print 'Hi.' # write to stdout
if __name__ == '__main__': Hello().mainloop()
% hello.py
Hi.
Hi.
¨ GUI classes can be extended by inheritance
¨ Subclasses may extend, or replace methods
¨ In OOP terms: a ‘is-a’ relationship
file: hellosub.py
#!/usr/local/bin/python
from hello import Hello # get superclass
from Tkinter import * # get Tkinter widgets
class HelloExtender(Hello): # is-a hello.Hello
def make_widgets(self): # extend method
Hello.make_widgets(self)
mine = Button(self, text='Extend',
command=self.quit)
mine.pack(side=RIGHT)
def onPress(self):
print 'Greetings!' # replace method
if __name__ == '__main__': HelloExtender().mainloop()
% python hellosub.py
Greetings!
Greetings!
¨ Frames can be attached to other Frames
¨ Tkinter records object tree internally
¨ In OOP terms: a ‘has-a’ relationship
file: hellouse.py
#!/usr/local/bin/python
from hello import Hello # get class to attach
from Tkinter import * # get Tkinter widgets
class HelloContainer(Frame): # has-a hello.Hello
def __init__(self, parent=None):
Frame.__init__(self, parent)
self.pack()
self.make_widgets()
def make_widgets(self):
mine = Button(self, text='Attach',
command=self.quit)
mine.pack(side=LEFT)
Hello(self) # attach a Hello to me
if __name__ == '__main__': HelloContainer().mainloop()
% hellouse.py
Hi.
Hi.
See “Extras\Gui” directory on class CD to run this example
from Tkinter import * # get base widget set
from glob import glob # file name expansion
import hellouseCheck # attach the last example to "me"
import random # pick a picture at random
gifdir = '../../../Part3/Gui/gifs/' # where to look for gif files
def draw():
name, photo = random.choice(images)
lbl.config(text=name)
pix.config(image=photo)
root=Tk()
lbl = Label(root, text="none", bg='blue', fg='red')
pix = Button(root, text="Press me", command=draw, bg='white')
lbl.pack(fill=BOTH)
pix.pack(pady=10)
hellouseCheck.HelloContainer(root, relief=SUNKEN, bd=2).pack(fill=BOTH)
files = glob(gifdir + "*.gif")
images = map(lambda x: (x, PhotoImage(file=x)), files)
print files
root.mainloop()
# 2d table of input fields
from Tkinter import *
rows = []
for i in range(5):
cols = []
for j in range(4):
e = Entry(relief=RIDGE)
e.grid(row=i, column=j, sticky=NSEW)
e.insert(END, '%d.%d' % (i, j))
cols.append(e)
rows.append(cols)
def onPress():
for row in rows:
for col in row:
print col.get(),
Button(text='Fetch', command=onPress).grid()
mainloop()
See Extras\Gui\Code to run this example
See Extras\Gui\Code to run this example
See Extras\Gui\Code to run this example
See Extras\Gui\Code to run this example
See CD’s top-level PP3E-Examples folder
Also available at http://examples.oreilly.com/python3/
¨ Portability
·
Tkinter programs run with native look-and-feel on X, MS-Windows,
Macintosh
¨ Other GUI widgets
·
25 widgets + dialogs, etc,: Text, Canvas, Listbox, Scrollbar, Image,
Menu, Entry, Radiobutton, Checkbutton, Scale,…
¨ Other Tkinter tools
·
File handlers, scheduled events, “grid” manager
·
Pmw (Python Mega Widgets), PIL (imaging), etc.; see Vaults site
·
Interactive GUI builders: PythonWorks?,
ActiveState Komodo
·
BoaConstructor, BlackAdder Gui buildes for wxPython, PyQt
¨ Implementation structure
·
Tk + C extension module + Python wrapper classes module
·
Uses extending (Tk lib) plus embedding (route events to handlers)
¨ Documentation
·
“Programming Python 2nd Edition”, Part II, 250 pages
·
“Programming Python 3rd Edition”, Part II, 300 pages
·
Other books: Manning book, upcoming O'Reilly book?
·
Tutorial,
reference: http://www.pythonware.com/library
·
Tcl/Tk books and manuals provide basic widget docs
¨ Other links
Extras\Gui\wxPython\wxPython.doc
(Tkinter/wxPython comparison)
Extras\Gui\Code (additional Tkinter examples)
http://examples.oreilly.com/python3/
(book examples)
See Also:
CD\PP3E-Examples\Distribution\PP3E-Examples-1.1\Examples\PP3E\Launch_PyDemos.pyw
Tkinter book examples on CD
wxPython.org
wxPython demo program
Click here to go to
lab exercises
Click here to go to exercise
solutions
Click here to go to
solution source files
Click here to go to
lecture example files