Python Crash Course: GUIs with Tkinter
Do you train for passing tests
or do you train for creative inquiry?
Noam Chomsky
Steffen Brinkmann
Max-Planck-Institut f¨
ur Astronomie, Heidelberg
IMPRESS, 2016
The ingredients
I
A working Python installation
I
Internet connection
I
Passion for Python
Outline
Motivation
To GUI or not to GUI
Getting started
Terminology
Hello World
The Widgets
Overview
Widget Properties and Placement
Putting it together
Motivation
To GUI or not to GUI
Outline
Motivation
To GUI or not to GUI
Getting started
Terminology
Hello World
The Widgets
Overview
Widget Properties and Placement
Putting it together
Motivation
To GUI or not to GUI
Why use GUIs?
I
Users are used to GUIs
I
Easy interaction
I
Display images, animations etc.
I
Visualise workflow
Motivation
To GUI or not to GUI
Why not use GUIs?
I
Faster development
I
Faster execution
I
Easier to test
I
Can be included in scripts (pipelines)
Motivation
To GUI or not to GUI
Why Tkinter?
I
Tkinter is the standard Python interface to the Tk GUI
toolkit.
I
No need to install additional packages
I
Simple enough to get quick results
I
Powerful enough for most applications
Motivation
To GUI or not to GUI
Get help
I
http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html
Getting started
Terminology
Outline
Motivation
To GUI or not to GUI
Getting started
Terminology
Hello World
The Widgets
Overview
Widget Properties and Placement
Putting it together
Getting started
Terminology
Terminology
I
Widget:
Visual element of interaction. Can be a container
(see below), control (Button, slider, . . . ), a display (label,
canvas,. . . ) or a combination of both (Text field, spin box)
I
Box, Container:
Widget that can contain one or more other
widgets.
Getting started
Terminology
Terminology
I
Event:
Events are created by the program itself (destroy,
resize, . . . ) or the user via controls (click button, mouse
move,. . . ).
I
Event handler:
Function or method dedicated to react to
events. Typically called on
event
.
I
Event loop:
separate execution thread or process which
checks for new events.
Getting started
Hello World
Outline
Motivation
To GUI or not to GUI
Getting started
Terminology
Hello World
The Widgets
Overview
Widget Properties and Placement
Putting it together
Getting started Hello World
Very simple
# !/ bin / env p y t h o n f r o m _ _ f u t u r e _ _ i m p o r t p r i n t _ f u n c t i o n i m p o r t sys if sys.v e r s i o n _ i n f o >= (3 ,): i m p o r t t k i n t e r as tk e l s e: i m p o r t T k i n t e r as tk top = tk.Tk() top.m a i n l o o p()I
The Tkinter module is called differently in Python 2 and 3
I
The class
Tk
represents the Tkinter framework and is
necessary for the event loop, exiting cleanly etc.
I
The function
mainloop
starts the event loop. It stops when
Getting started
Hello World
A little less simple
c l a s s H e l l o(tk.F r a m e): def _ _ i n i t _ _(self, m a s t e r=tk.Tk( ) ) : tk.F r a m e._ _ i n i t _ _(self, m a s t e r) s e l f.m a s t e r=m a s t e r s e l f.g r i d() s e l f.c r e a t e W i d g e t s() def c r e a t e W i d g e t s(s e l f): s e l f.b u t t o n 1 = tk.B u t t o n(self, t e x t=" c l i c k me ", c o m m a n d=s e l f.s a y _ h e l l o) s e l f.b u t t o n 1.g r i d(row=10 , c o l u m n= 1 0 ) s e l f.b u t t o n _ q u i t = tk.B u t t o n(self, t e x t=" Q U I T ", fg=" red ", c o m m a n d=s e l f.m a s t e r.d e s t r o y) s e l f.b u t t o n _ q u i t.g r i d(row=20 , c o l u m n= 1 0 ) def s a y _ h e l l o(s e l f): p r i n t(" h e l l o there , e v e r y o n e ! ") app = H e l l o() app.m a i n l o o p()
Getting started
Hello World
A little less simple
I
It is convenient to create an application class, derived from
tk.Frame
I
Widgets can be added to the application window by
grid()
,
The Widgets
Overview
Outline
Motivation
To GUI or not to GUI
Getting started
Terminology
Hello World
The Widgets
Overview
Widget Properties and Placement
Putting it together
The Widgets
Overview
Overview
Frame and Buttons
Frame
The Frame widget is used as a container widget to
organize other widgets.
Button
The Button widget is used to display buttons in your
application.
Checkbutton
The Checkbutton widget is used to display a number of
options as checkboxes. The user can select multiple
options at a time.
Radiobutton
The Radiobutton widget is used to display a number of
options as radio buttons. The user can select only one
option at a time.
The Widgets
Overview
Overview
Text and Displays
Label
The Label widget is used to provide a single-line caption
for other widgets. It can also contain images.
Message
The Message widget is used to display multiline text fields.
Entry
The Entry widget is used to display a single-line text field
for accepting values from a user.
Spinbox
The Spinbox widget is a variant of the standard Tkinter
Entry widget, which can be used to select from a fixed
number of values.
Text
The Text widget is used to display text in multiple lines.
Canvas
The Canvas widget is used to draw shapes, such as lines,
The Widgets
Overview
Overview
Menus and more choices and controls
Menubutton
The Menubutton widget is used to display menus in your
application.
Menu
The Menu widget is used to provide various commands to
a user.These commands can be contained inside
Menubutton or set as the main menu.
Listbox
The Listbox widget is used to provide a list of options to a
user.
Scale
The Scale widget is used to provide a slider widget.
Scrollbar
The Scrollbar widget is used to add scrolling
The Widgets
Overview
Overview
Containers
Toplevel
The Toplevel widget is used to provide a separate window
container.
PanedWindow
A PanedWindow is a container widget that may contain
any number of panes, arranged horizontally or vertically.
LabelFrame
A labelframe is a simple container widget. Its primary
purpose is to act as a spacer or container for complex
window layouts.
The Widgets
Overview
Overview
Dialogues
tkMessageBox
This module is used to display message boxes in your
applications.
tkFileDialog
This module provides two different pop-up windows you
can use to give the user the ability to find existing files or
create new files.
tkColorChooser
Module featuring a dialogue to select a colour.
The Widgets
Widget Properties and Placement
Outline
Motivation
To GUI or not to GUI
Getting started
Terminology
Hello World
The Widgets
Overview
Widget Properties and Placement
Putting it together
The Widgets
Widget Properties and Placement
Setting Widget Properties
During Initialisation
b u t t o n
=
tk
.
B u t t o n
(
parent
,
t e x t
=
’ b u t t o n l a b e l ’
,
c o m m a n d
=
s e l f
.
o n _ b u t t o n
)
I
The only positional argument
parent
specifies in whose grid
the widget will be displayed.
The Widgets
Widget Properties and Placement
Setting Widget Properties
Using
config()
b u t t o n
=
tk
.
B u t t o n
(
p a r e n t
)
b u t t o n
.
c o n f i g
(
t e x t
=
’ b u t t o n l a b e l ’
)
b u t t o n
.
c o n f i g
(
c o m m a n d
=
s e l f
.
o n _ b u t t o n
)
I
parent
still has to be set when constructing the widget.
I
Options are set as keyword arguments in method
config
:
config(option=value)
I
calling
config()
without arguments returns a dictionary of
all the widget’s current options.
I
The method
cget(option)
returns the value of a single
The Widgets
Widget Properties and Placement
Setting Widget Properties
Using Widget as Dictionary
b u t t o n
=
tk
.
B u t t o n
(
p a r e n t
)
b u t t o n
[
’ t e x t ’
] =
’ b u t t o n l a b e l ’
b u t t o n
[
’ c o m m a n d ’
] =
s e l f
.
o n _ b u t t o n
I
parent
still has to be set when constructing the widget.
The Widgets
Widget Properties and Placement
Postioning Widgets
Overview
I
grid()
: Arrange widget on e rectangular grid, i.e. in rows
and columns. Recommended.
I
pack()
: Arrange widgets by stacking them vertically or
horizontally. Very limited.
I
place()
Place widgets at specific coordinates. Most (too
The Widgets
Widget Properties and Placement
Postioning Widgets
c l a s s H e l l o(tk.F r a m e): def _ _ i n i t _ _(self, m a s t e r=tk.Tk( ) ) : tk.F r a m e._ _ i n i t _ _(self, m a s t e r) s e l f.m a s t e r=m a s t e r s e l f.g r i d() s e l f.c r e a t e W i d g e t s() def c r e a t e W i d g e t s(s e l f): s e l f.b u t t o n 1 = tk.B u t t o n(self, t e x t=" c l i c k me ", c o m m a n d=s e l f.s a y _ h e l l o) s e l f.b u t t o n 1.g r i d(row=10 , c o l u m n= 1 0 ) s e l f.b u t t o n _ q u i t = tk.B u t t o n(self, t e x t=" Q U I T ", fg=" red ", c o m m a n d=s e l f.m a s t e r.d e s t r o y) s e l f.b u t t o n _ q u i t.g r i d(row=20 , c o l u m n= 1 0 ) def s a y _ h e l l o(s e l f): p r i n t(" h e l l o there , e v e r y o n e ! ") app = H e l l o() app.m a i n l o o p()The Widgets
Widget Properties and Placement
Postioning Widgets
grid()
I
grid()
places the widget in tk’s geometry manager.
I
Use grid in the top level widget (e.g.
Frame
or other
container) to initialise the grid.
I
Call grid for every widget with the keywords
row
and
column
.
I
Cover more rows and/or columns:
columnspan
,
rowspan
I
Use
sticky
argument to align (e.g.
tk.E
,
tk.NW
) or stretch
(e.g.
tk.N+tk.S
) the widget.
The Widgets
Widget Properties and Placement
Exercise
Conversion tool
Write a program that converts meter to parsec and vice versa:
Putting it together
More complexity
Outline
Motivation
To GUI or not to GUI
Getting started
Terminology
Hello World
The Widgets
Overview
Widget Properties and Placement
Putting it together
More complexity
Putting it together
More complexity
Control Variables
I
Control variables can be
I
tk.StringVar
I
tk.IntVar
I
tk.DoubleVar
I
Get and set values with
get()
and
set()
.
I
Use them to store the Data independently from the visual
Putting it together
More complexity
Matplotlib in tkinter
I
For simple plot,
tk.Canvas
may suffice
I
For displaying Matplotlib plots in tkinter programs, use
FigureCanvasTkAgg
:
i m p o r t m a t p l o t l i b m a t p l o t l i b.use(’ T k A g g ’)
f r o m m a t p l o t l i b.b a c k e n d s.b a c k e n d _ t k a g g i m p o r t F i g u r e C a n v a s T k A g g
Putting it together
More complexity
Putting it together More complexity
Matplotlib in tkinter
f r o m n u m p y i m p o r t * i m p o r t m a t p l o t l i b m a t p l o t l i b.use(’ T k A g g ’) f r o m m a t p l o t l i b.b a c k e n d s.b a c k e n d _ t k a g g i m p o r t F i g u r e C a n v a s T k A g g f r o m m a t p l o t l i b.f i g u r e i m p o r t F i g u r e c l a s s F i t t i n g(tk.F r a m e): def _ _ i n i t _ _(self, m a s t e r=tk.Tk( ) ) : tk.F r a m e._ _ i n i t _ _(self, m a s t e r) s e l f.m a s t e r=m a s t e r s e l f.g r i d() s e l f.c r e a t e V a r i a b l e s() s e l f.c r e a t e W i d g e t s() def c r e a t e V a r i a b l e s(s e l f): s e l f.e _ i n p u t _ t e x t = tk.S t r i n g V a r() s e l f.e _ i n p u t _ t e x t.set(’ sin ( x ) ’). . .
Putting it together More complexity
Matplotlib in tkinter
def c r e a t e W i d g e t s(s e l f): # m a t p l o t l i b F i g u r e C a n v a s T k A g g f = F i g u r e(f i g s i z e=(5 , 4) , dpi= 1 0 0 ) s e l f.sp = f.a d d _ s u b p l o t( 1 1 1 ) s e l f.x = l i n s p a c e( -10 ,10 ,200) x = s e l f.x y = e v a l(s e l f.e _ i n p u t _ t e x t.get()) s e l f.sp.p l o t(x, y) s e l f.c a n v a s = F i g u r e C a n v a s T k A g g(f, m a s t e r=s e l f) s e l f.c a n v a s.s h o w() s e l f.c a n v a s.g e t _ t k _ w i d g e t().g r i d(row = 2 , c o l u m n=10 , c o l u m n s p a n=20 , s t i c k y=tk.N S E W) # e n t r y s e l f.e _ i n p u t = tk.E n t r y(self, t e x t v a r i a b l e=s e l f.e _ i n p u t _ t e x t) s e l f.e _ i n p u t.g r i d(row=5 , c o l u m n=10 , c o l u m n s p a n=20 , s t i c k y=tk.EW) # b u t t o n s s e l f.b _ p l o t = tk.B u t t o n(self, t e x t=" P l o t ", c o m m a n d=s e l f.o n _ p l o t) s e l f.b _ p l o t.g r i d(row=10 , c o l u m n=10 , s t i c k y=tk.EW) s e l f.b _ q u i t = tk.B u t t o n(self, t e x t=" Q u i t ", c o m m a n d=s e l f.m a s t e r.d e s t r o y) s e l f.b _ q u i t.g r i d(row=10 , c o l u m n=20 , s t i c k y=tk.EW) def o n _ p l o t(s e l f): x = s e l f.x y = e v a l(s e l f.e _ i n p u t _ t e x t.get()) s e l f.sp.p l o t(x, y) s e l f.c a n v a s.s h o w() app = F i t t i n g()Putting it together
More complexity
Loading files conveniently
I
Let the user choose the file to load using the
tkFileDialog
if sys.v e r s i o n _ i n f o >= (3 ,): f r o m t k i n t e r.f i l e d i a l o g i m p o r t a s k o p e n f i l e n a m e e l s e: f r o m t k F i l e D i a l o g i m p o r t a s k o p e n f i l e n a m e f i l e n a m e _ w i t h _ p a t h = a s k o p e n f i l e n a m e() d a t a = np.l o a d t x t(f i l e n a m e _ w i t h _ p a t h, u n p a c k=T r u e)
I
To let the user choose a filename for saving data (i.e. creating
Putting it together
More complexity
Menus in tkinter
I
Create menus with
tk.Menu
I
Add items to the menu using
add command()
I
Add a submenu using
add cascade()
.
I
Add a separator using
add separator()
.
I
Finally set the menu as the programs main menu with
Putting it together More complexity
Menus in tkinter
c l a s s J u s t M e n u(tk.F r a m e): def _ _ i n i t _ _(self, m a s t e r=tk.Tk( ) ) : tk.F r a m e._ _ i n i t _ _(self, m a s t e r) s e l f.m a s t e r=m a s t e r s e l f.c o n f i g(w i d t h= 3 0 0 ) s e l f.c o n f i g(h e i g h t= 2 0 0 ) s e l f.g r i d() s e l f.c r e a t e M e n u() def c r e a t e M e n u(s e l f): m e n u b a r = tk.M e n u(s e l f.m a s t e r) f i l e m e n u = tk.M e n u(menubar, t e a r o f f=1) f i l e m e n u.a d d _ c o m m a n d(l a b e l=" New ", c o m m a n d=s e l f.d o n o t h i n g, u n d e r l i n e=0) f i l e m e n u.a d d _ c o m m a n d(l a b e l=" O p e n ", c o m m a n d=s e l f.d o n o t h i n g) f i l e m e n u.a d d _ c o m m a n d(l a b e l=" S a v e ", c o m m a n d=s e l f.d o n o t h i n g) f i l e m e n u.a d d _ c o m m a n d(l a b e l=" S a v e as ... ", c o m m a n d=s e l f.d o n o t h i n g) f i l e m e n u.a d d _ c o m m a n d(l a b e l=" C l o s e ", c o m m a n d=s e l f.d o n o t h i n g) f i l e m e n u.a d d _ s e p a r a t o r() f i l e m e n u.a d d _ c o m m a n d(l a b e l=" E x i t ", c o m m a n d=s e l f.m a s t e r.q u i t) m e n u b a r.a d d _ c a s c a d e(l a b e l=" F i l e ", m e n u=f i l e m e n u, u n d e r l i n e=0) s e l f.m a s t e r.c o n f i g(m e n u=m e n u b a r) def d o n o t h i n g(s e l f): p r i n t(’ do n o t h i n g ’) app = J u s t M e n u()Putting it together
More complexity
Exercise
I
Download the data file:
www.mpia.da/˜ brinkmann/PythonCrash/fitting.dat
I
Write a program that implements a button to load and display
the data in a plot.
I
Extend this program to feature three slide controls
(
tk.Scale
), which control a, b and c in this function
def m o d e l(x,a,b,c):
r e t u r n a*x**2 + b*x + c
I
Plot the parabola in the same axes as the data. It should
update whenever the slide controls are changed.
Appendix
For Further Reading
For Further Reading I
J. E. Grayson
Python and Tkinter Programming
.
Manning Publications, 2000.
B. Chaudhary
Tkinter GUI Application Development
.
Packt Publishing, 2013.