11. GUI programming

 

 

 

 

 

 

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

 

 


 

Python GUI Options

 

 

 

¨  Tkinter

·        Python’s OO interface to the portable Tk API

·        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 API originally developed by John Ousterhout

 

 

 

 

¨  wxPython

·        Second most popular GUI API for Python (?)

·        Portable GUI class library written in C++ (X, Windows, Mac)

·        Wraps a C++ API: wxWindows + wxPython

·        Rich widget set: trees, html viewers, notebooks

·        Tends to be more complex: C++ API (wx) verses scripting API (Tk)

·        Was less documented, but wxPython book in 2006

·        GUI builders: BoaConstructor, wxDesigner

·        Tkinter + PMW package roughly as rich as wxPython

 

 

 

¨  PyQt, PyGTK

·        From KDE & Gnome Linux libraries, but now portable

·        PyQt third most popular GUI API for Python (?)

·        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)

·        MFC integration for Python on Windows (only)

 

 

¨  Jython (a.k.a. Jpython)

·        Access to Java GUI APIs: AWT, Swing, etc.

 

 

¨  IronPython .NET/Mono port

·        .NET may provide GUI tools

 

 

¨  PythonCard

·        API + drag-and-drop builder on top of wxPython

 

 

 

¨  Dabo

·        3-tier application builder with GUI, Dbase, logic

 

 

¨  Anygui

·        Portable API implemented on top of Tk, wx, Qt

 

 

 

 

See: Extras\Gui\wxPython\wxPython.doc on CD for Tkinter, wxPython comparisons


 

 

 

 

The Tkinter ‘hello world’ program

 

 

 

¨   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

 

 

 

 

 

 


 

Adding buttons, frames, and callbacks

 

 

¨   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

 

Getting input from a user

 

 

¨   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()

 

 

 

 

 

 

 

More details

 

 

 

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

 

 

 

 

 

 


OOP: Building GUIs by subclassing frames

 

 

¨   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.

 

 

 


 

 

OOP: Reusing GUIs by subclassing, ‘is-a’

 

 

 

¨   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!

 

 

 

 


 

OOP: Reusing GUIs by attaching, ‘has-a’

 

 

 

¨   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.

 

 

 

 

 

 

Images

 

 

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()

 

 

 

 


 

 

 

 

Grid layouts

 

 

# 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(),

        print

 

Button(text='Fetch', command=onPress).grid()

mainloop()

 

 

 

 


 

 

 

 

Canvas, Text, dialogs, and Toplevel

 

 

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

 

 

 

 

 

 

 

Larger examples: Programming Python, Editions 2+

 

 

 

See CD’s top-level PP3E-Examples folder

Also available at http://examples.oreilly.com/python3/

 

 

 

A clock drawn on a canvas and updated with a timer, embedded picture

 

 

 

 

 

 

A calculator: frames of buttons, popup history, command lines, key bindings

 

 

 

 

 

 

An artificially intelligent tic-tac-toe game: labels and mouse event bindings

 

 

 

 

 

 

A text editor object/program: menus, text, scrollbars, toolbar frame

 

 

 

 

 

 

A demo launcher button bar: os.fork() on Linux, os.spawnv() on Windows

 

 

 

 

 

 

A generic tree data structure drawer: canvas, lines, event bindings

 

 

 

 

 

 

An image file slideshow: embeds text editor, picture, scale, timer, etc.

 

 

 

 

 

 

A table browser GUI: listboxes, forms, persistence, etc.

 

 

 

 

 

 

A drawing program: draw and move graphic objects

 

 

 

 

 

 

A POP/SMTP email client in Python/Tk, embeds text editor

(a beta version is included in the class Internet Examples directory)

 

 

 

 

 

 

 

 

 

 

 

 

Tkinter odds and ends

 

 

 

¨  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

 

 

 

Lab Session 8

 

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