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: simple code for simple GUIs

●      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: [tT]kinter + Tk lib + (X, Windows, Mac libs)

●      A de-facto standard: Tk used by Python, Perl, and TCL

●      An open source system, supported/used by many

 

 

 

♦     wxPython: complex code for richer GUIs

●      Second most popular GUI API for Python (or is it PyQt?)

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

●      Wraps a C++ API: wxWidgets + 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: on the order of wxPython

●      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: was not completely open source (but is today)

●      Qt GUI builders: BlackAdder, QT Designer

●      Example use case: free Calibre ebook viewer

 

 

♦     Jython (a.k.a. Jpython, originally)

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

 

 

♦     IronPython .NET/Mono port

●      .NET may provide GUI tools usable in Python scripts

 

 

♦     Rich Internet Applications (RIAs)

●      Blurs line between “desktop” and web clients/GUIs

●      Run in a web browser, javascript/ajax to be dynamic

●      Gains browser portability at cost in software stack depth

●      Pyjamas—now Pyjs (Py=>JS compiler, GWT toolkit), Silverlight (IronPython), Flex, etc.

 

 

♦     PyWin32 (former known as win32all)

●      MFC integration for Python on Windows (only)

 

 

♦     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\Code\Gui\wxPython\wxPython.doc on CD for Tkinter, wxPython comparisons


 

 

 

 

The Tkinter ‘hello world’ program

 

 

 

♦     Widgets: class instances

♦     Options: keyword arguments

♦     [tT]kinter exports classes and constants

♦     Widgets must be packed (or gridded, placed)

♦     ‘mainloop’ shows widgets, catches events

♦     3.X: ‘Tkinter’→‘tkinter’, supplemental modules renamed

 

 

 

 

 

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

 

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: gui1

 

 

 


 

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

 

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: gui2

 

 

 

 

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

 

 

 

 

 

 

 

Assorted [tT]kinter 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

 

 

 

 

 

 

 

 

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.

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: hello

 


 

 

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!

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: hellosub

 

 


 

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.

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: hellouse

 

 

 

 

Images

 

 

See “Extras\Code\Gui\Code” directory on class CD to run this example

As of Python 3.4, tkinter supports PNG, GIF, amd PPM/PPG; install Pillow for others

              

 

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

# see also frigcal’s uniform gridding: tables

 

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

 

(Some of the following may be in 2.X form: convert to run on 3.X)

 

 

See Extras\Code\Gui\Code to run this example

 

 

 

 

See Extras\Code\Gui\Code to run this example

 

 

 

 

 

See Extras\Code\Gui\Code to run this example

 

 

 

 

 

 

 

 

See Extras\Code\Gui\Code to run this example

 

 

 

 

 

 

 

Larger examples: Programming Python, Editions 2+

 

 

 

See learning-python.com/gadgets for more sceenshots

See CD’s top-level Extras\PP4E-Examples folder for code

Also available at http://learning-python.com/books/about-pp4e.html

 

 

 

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 (old, new)

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: pyedit-1

 

 

 

 

 

 

 

A photo viewer, with thumbnails, resizing

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: http://learning-python.com/gadgets/pyphoto.png

 

 

 

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.

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: pyform-1

 

 

 

 

A drawing program: draw and move graphic objects

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: pydraw-1

 

 

 

 

A POP/SMTP email client in Python/Tk, embeds text editor (old, new)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Larger Examples: frigcal, mergeall (2015)

 

See CD’s top-level Extras\frigcal-mergeall folder

Click images below for larger versions on the web

 

 

Description: Description: Description: C:\Users\mark\Desktop\000-latest-composite.png

 

 

 

Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: Description: http://learning-python.com/frigcal/screenshots/New-Version1.6/v1.6-ubuntu-linux.png

 

 

 

Description: Description: Description: C:\Users\mark\Desktop\main-quit-help.png

 

 

 

 

Tkinter odds and ends

 

 

 

♦     Portability

●      [tT]kinter programs run with native look-and-feel on X, MS-Windows, Macintosh

●      Vast majority of code runs unchanged across different platforms

●      But some aspects are platform-specific, especially window manager context (icons, modal dialogs)

 

 

♦     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, drag-and-drop, tix and themes

●      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

●      “Programming Python 4th Edition”, Part III 400 pages, + other parts: email client

●      Other books: Manning book (somewhat dated), and others (see Amazon)

●      Tcl/Tk books and manuals also provide basic widget docs

●      Tutorial, reference: http://effbot.org/tkinterbook/

●      Reference: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html

●      Wiki: https://wiki.python.org/moin/TkInter

 

 

♦     Other links

Extras\Code\Gui\wxPython\wxPython.doc (Tkinter/wxPython comparison)

Extras\Code\Gui\Code (additional Tkinter examples)

Extras\PP3E-Examples (book GUI examples, Python 2.X)

Extras\PP4E-Examples (book GUI examples, Python 3.X)

 


See Also:

 

Extras\PP4E-Examples → PP4E-Examples-1.4\Examples\PP4E\Launch_PyDemos.pyw

               [tT]kinter book examples in class package (or use PP3E-Examples directory for Python 2.X)

 

 

 

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