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