Tkinter Tutorial
Tkinter Tutorial
Tkinter Tutorial
Release 2020
Raphael Holzer
1 Introduction 3
1.1 Our first program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 The same in OOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Classic and themed widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Setting options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5 Let’s define our own widget class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.6 Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.7 Radiobutton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.8 Checkbutton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.9 Entry field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.10 The tklib module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2 Button 13
2.1 A one-button program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Convert feet to meters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4 Event bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5 Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.6 Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.7 Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3 Radio Button 21
3.1 Standard Radiobutton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2 Using a list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.3 A better Radiobutton class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4 If something goes wrong . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4 Checkbutton 27
4.1 The standard checkbutton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.2 A better Checkbutton class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
i
5.6 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.7 Another exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.8 Spinbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.9 Scale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.10 Final implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
7 Basic widgets 45
7.1 Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.2 Buttons which create buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.3 Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.4 Display a label with an image with . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
7.5 Display a images as labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.6 Display a images as buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
7.7 Display a images in a listbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.8 Embedded frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.9 Embedded frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8 Events 55
8.1 Write events to the status bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
8.2 Write events to a text widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8.3 Enter, leave and return events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.4 Keyboard events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
9 Listbox 63
9.1 Create a listbox the old way . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
9.2 Create a listbox the new way . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.3 Single and extended selection mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
9.4 ListboxSelect callback function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.5 Edit a listbox item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.6 Listbox with search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
9.7 Regular expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
9.8 Regular expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
10 Menu 75
10.1 Adding a menu bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
10.2 Adding items to the menu bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
10.3 Menus with sub-menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
10.4 Insert an item at a specific position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.5 Different menus for each window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.6 Creating new widgets from the menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
10.7 Insert a popup menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
11 Canvas 87
11.1 Draw lines and rectangles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
11.2 Create text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
11.3 Paint with ovals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
11.4 Polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
11.5 Random circles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
11.6 Canvas configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
11.7 Canvas configuration with tree view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
11.8 Draw shapes with the mouse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
11.9 Draw straight lines with the mouse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
ii
12 Scrollbar 99
12.1 Listbox with scrollbars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
12.2 Text with scrollbars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
12.3 Canvas with scrollbars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
12.4 Sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
13 Text 105
13.1 Display multi-line text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
13.2 Edit text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
13.3 Undo and redo text edit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
13.4 Format text with tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
13.5 Add custom formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
13.6 Place widgets inside text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
13.7 Search inside text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
13.8 Show a help text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
14 Treeview 115
14.1 Multiple columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
14.2 Configure style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
14.3 Bind to events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
14.4 Two treeviews next to each other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
14.5 Display a 2D table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
14.6 Insert items into a treeview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
14.7 Add items to specific column . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
14.8 Customize the treeview widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
15 Windows 127
15.1 Create new windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
15.2 Standard dialogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
15.3 Open dialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
15.4 Alert and confirmation dialogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
15.5 Add widgets and separators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
15.6 The Labelframe widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
15.7 Paned windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
15.8 Tabbed notebooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
15.9 Add more tabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
16 Time 139
16.1 Clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
16.2 Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
17 Applications 143
17.1 Calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
iii
iv
tk tutorial Documentation, Release 2020
Tk is a graphical user interface (GUI) library. It allows to create windows, buttons and all the other graphical
elements. This tutorial shows how to use object-oriented programming (OOP) for making applications with the Tk
framework.
Contents: 1
tk tutorial Documentation, Release 2020
2 Contents:
CHAPTER 1
Introduction
It is somewhat of a tradition for programming tutorials to start with a program which writes hello world to the
computer screen. Here is the result of this standard initiation ritual:
So how do we do this ? First we have to import the module tkinter (Tk interface) and give it the shortcut tk:
import tkinter as tk
Then we create the root widget with class tk.Tk which becomes the root for all other widgets:
3
tk tutorial Documentation, Release 2020
root = tk.Tk()
Then we create a label widget with class tk.Label which has root as parent and hello world as text attribute:
Then we have to call a placement method such as grid(), to make the label appear inside the window:
label.grid()
Finally we call the main loop method tk.mainloop() which runs continually until the window close button is
clicked or the quit Python menu is chosen:
root.mainloop()
This method call is usully the last one in the program, after all the graphical elements and callback functions have been
defined.
intro1.py
import tkinter as tk
root = tk.Tk()
label = tk.Label(master=root, text='hello world!', font='Arial 24')
label.grid()
root.mainloop()
Now we rewrite this first program in OOP manner. We start by defining the new App class:
class App:
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(self.root, text='hello world!', font='Arial 24')
self.label.grid()
In case we do not need to keep a reference to the label object, we can shorten the last two lines to:
def run(self):
"""Run the main loop."""
self.root.mainloop()
4 Chapter 1. Introduction
tk tutorial Documentation, Release 2020
App().run()
import tkinter as tk
class App:
"""Define the application class."""
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(self.root, text='hello world!', font='Arial 24')
self.label.grid()
def run(self):
"""Run the main loop."""
self.root.mainloop()
App().run()
intro2.py
The elements of a graphical user interface are called widgets. In Tk there are two generations of widgets:
• the old classic tk widgets, originally introduced in 1991
• the new themed ttk widgets, added in 2007 with version 8.5
The new themed widgets can be found in the submodule tkinter.ttk. Whenever a newer themed widget is
available, we will use it. We import the classic and the new themed widgets with this import statement:
import tkinter as tk
import tkinter.ttk as ttk
tk.Label(self.root, text='tk.Label').pack()
ttk.Label(self.root, text='ttk.Label').pack()
tk.Button(self.root, text='tk.Button').pack()
ttk.Button(self.root, text='ttk.Button').pack()
The screen capture below shows the difference in appearance. The new themed widgets (ttk) have a gray background
and the buttons have uniform size.
import tkinter as tk
import tkinter.ttk as ttk
class App:
"""Define the application class."""
def __init__(self):
self.root = tk.Tk()
self.root.title('App')
tk.Button(self.root, text='tk.Button').grid()
ttk.Button(self.root, text='ttk.Button').grid()
def run(self):
"""Run the main loop."""
self.root.mainloop()
App().run()
intro3.py
6 Chapter 1. Introduction
tk tutorial Documentation, Release 2020
# setting options
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
ttk.Button(root, text='Set options at creation').grid()
button = ttk.Button(root)
button['text'] = 'Set options as dict'
button.grid()
button = ttk.Button(root)
button.config(text='Set options with config() method')
button.grid()
options = button.config()
for x in options:
print(x, options[x])
print(button.keys())
root.mainloop()
intro4.py
We are now going to redefine the original tk and ttk classes to make our own Tk widget classes. This new classes have
the following advantages:
• the text option has a default value (Label, Button, etc.)
• the parent object is automatically set (root)
• all keyword arguments are passed on (kwargs)
• the themed version is used when available (ttk)
This is our new Label class based on the original themed class:
class Label(ttk.Label):
"""Create a Label object."""
def __init__(self, text='Label', **kwargs):
super().__init__(App.stack[-1], text=text, **kwargs)
self.grid()
class Button(ttk.Button):
"""Create a Button object."""
def __init__(self, text='Button', **kwargs):
super().__init__(App.stack[-1], text=text, **kwargs)
self.grid()
1.6 Button
Buttons can be clicked and are used to execute a command associated with them. The following demo creates 4
buttons.
Button('Start', 'print("Start")')
Button('Stop', 'print("Stop")')
Button('Self', 'print(self)')
Button('Destroy', 'self.destroy()')
app.run()
intro5.py
1.7 Radiobutton
Radiobuttons are active elements which can be clicked and execute actions. Only one button is active at any one time.
8 Chapter 1. Introduction
tk tutorial Documentation, Release 2020
app.run()
intro6.py
1.8 Checkbutton
Checkbuttons are active elements which can be clicked and execute actions. Multiple checkbuttons can be selected
simultaneously.
app.run()
1.8. Checkbutton 9
tk tutorial Documentation, Release 2020
intro7.py
Entry entry field presents the user with a single line text field where he can enter a string value.
intro8.py
In the following section we are going to redefine the tk and ttk objects. To make it easier to use them, we follow
these design principles:
• we keep the excact same class names
• the parent object is chosen automatically
• all keyword arguments are forwarded
The first widget to consider is the Label which just places static text. Where it makes sense, a label will be combined
with a button or entry widget.
There are three types of buttons:
• Button
• Checkbutton
• Radiobutton
10 Chapter 1. Introduction
tk tutorial Documentation, Release 2020
There are four types of entry widgets for text or numbers, which allow to input text with the keyboard or making a
choice uint the mouse:
• Entry
• Combobox
• Spinbox
• Scale
Then there are the two complex display widgets for text and graphics:
• Text
• Canvas
These two widgets present lists:
• Listbox
• Treeview
Finally these widgets are helper widgets:
• Frame
• Separator
• Window
• Scrollbar
• SizeGrip
• Progressbar
• Menu
• ContextMenu
• Panedwindow
12 Chapter 1. Introduction
CHAPTER 2
Button
Let’s start with a simple example of creating a button which displays some text.
First we import the tkinter module and give it the shorter name tk:
import tkinter as tk
Then we create a Tk root object which represents the window and will be the parent for all the other widgets:
root = tk.Tk()
Then we create a button object which has root as parent, and to which we give the text Hello world. This object calls
the method pack() which makes the button visible in the window. Finally root calls the mainloop() method to
start the program:
13
tk tutorial Documentation, Release 2020
root = tk.Tk()
tk.Button(root, text="Hello World").pack()
root.mainloop()
button1.py
Now let’s create a real application which does something useful. The following program has an input entry field, a
button and an output label. When you press the button (or hit the return key) it converts feet to meters.
After importing the classic Tk module as tk we create the root object and set a descriptive window title:
import tkinter as tk
root = tk.Tk()
root.title("Feet to meters")
14 Chapter 2. Button
tk tutorial Documentation, Release 2020
Two of the widgets, the entry widget and the label widget, have special StringVar variables:
feet = tk.StringVar()
meters = tk.StringVar()
Finally we bind the calculate function also to the Return key and start the main loop:
root.bind('<Return>', calculate)
root.mainloop()
The conversion is done by calling the calculate function which gets the feet value from the StringVar feet,
converts the value to meters and sets the StringVar meters. We enclose the calculation inside a try-except
statement to account for value errors, in case the input string is not numeric.
def calculate(*args):
try:
value = float(feet.get())
meters.set(0.3048 * value)
except ValueError:
pass
button2.py
import tkinter as tk
root = tk.Tk()
root.title("Feet to meters")
feet = tk.StringVar()
meters = tk.StringVar()
def calculate(*args):
try:
value = float(feet.get())
meters.set(0.3048 * value)
except ValueError:
pass
root.bind('<Return>', calculate)
root.mainloop()
2.3 Concepts
Each widget in Tk can have event bindings. In the following example we bind a function to these events:
• enter the widget
• leave the widget
• click the mouse button
Tk expects an event callback function which has an event object as its first argument. Here we define a lambda
function with an event argument e, but we do not use it here.
Event handlers can be set up for:
• the individual widget
• a class of widgets
• the toplevel window
16 Chapter 2. Button
tk tutorial Documentation, Release 2020
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text='starting...', font='Arial 36')
label.pack()
root.mainloop()
bind1.py
2.5 Frame
The frame widget displays just a rectangle. It primarily is used as a container for other widgets. A frame has these
common options:
• padding - extra space inside the frame
• borderwidth
• relief (flat, raised, sunken, solid, ridge, grove)
• width
• height
The example below shows the 6 different relief types and uses a borderwidth of 5.
import tkinter as tk
root = tk.Tk()
2.5. Frame 17
tk tutorial Documentation, Release 2020
root.mainloop()
frame1.py
2.6 Label
The label widget displays a static text, for example the text next to an entry. User do normally not interact with a label.
Common options are:
• text - a static text
• textvariable - a dynamic text from a variable
• image - an image to be displayed
• compound - center, top, bottom, left, right (text position in in relation to image)
• justifiy - left, center, right
• wraplength - linelength for long labels
The following example shows a label with a static text and another with a dynamic text. If both are defined, the dynamic
text will have precedence. The font keyword takes a string with the font family and font size. The foreground
keyword takes a color string.
import tkinter as tk
root = tk.Tk()
str = tk.StringVar(value='dynamic text')
root.mainloop()
18 Chapter 2. Button
tk tutorial Documentation, Release 2020
label1.py
Labels also accept the relief keyword.
import tkinter as tk
root = tk.Tk()
root.mainloop()
label2.py
2.7 Button
Buttons have a command keyword which allows to specify a function. This function is called, but without an argu-
ment. We can use the lambda function to create a function on the fly and provide an argument.
import tkinter as tk
root = tk.Tk()
def callback(x):
print('button', x)
root.mainloop()
button3.py
Pressing the 3 buttons one after another writes this to the console:
button 1
button 2
button 3
2.7. Button 19
tk tutorial Documentation, Release 2020
20 Chapter 2. Button
CHAPTER 3
Radio Button
A radiobutton lets you choose among a number of mutually exclusive options. Radiobuttons are used together in a
set and are appropriate when the number of choices is fairly small (about 3-5).
A Radiobutton object has these attributes:
• parent - the parent object
• text - the text label to display
• command - the callback function
• variable - the variable shared among radiobuttons of a set
• value - the specific value of the radiobutton
21
tk tutorial Documentation, Release 2020
import tkinter as tk
root = tk.Tk()
var = tk.StringVar()
var.set('English')
def cb():
print(var.get())
root.mainloop()
radio1.py
The radiobutton code consists of 7 lines and has a lot of repeated parts.
A better way would be to use a list. The code still has 7 lines, but when we increase the number of items, the code
length remains constant.
import tkinter as tk
root = tk.Tk()
def cb():
print(var.get())
for x in items:
tk.Radiobutton(root, text=x, variable=var, value=x, command=cb).grid()
(continues on next page)
root.mainloop()
radio2.py
It’s time now to redefine the Radiobutton class to create everything in just one line:
Radiobutton('English;German;French', 'print(self.item)')
"""Create radiobuttons."""
from tklib import *
app = App()
Radiobutton('English;German;French', 'print(self.item)')
app.run()
radio3.py
Now let’s see how this class is defined
class Radiobutton:
"""Create a list-based Radiobutton object."""
def cb(self):
"""Evaluate the cmd string in the Radiobutton context."""
self.item = self.items[self.val.get()]
exec(self.cmd)
The item string is split at the semicolon into a regular list. The shared variable is a IntVar object. Each radiobutton
has an integer value (0, 1, 2, . . . ). The callback function finds the selected item by looking up this integer value in the
items list.
Let’s look at another exemple. This time we add another language (Italian) and initialize the default button to 2
(French).
app = App('Radiobuttons')
Radiobutton('English;German;French;Italian', 'print(self.item)', 2)
app.run()
radio4.py
If there is no items list, there will be a single item called Radiobutton. If there is an error in the expression, this
message is written to the console:
app = App('Radiobuttons')
Radiobutton() # no item list
Radiobutton('A;B', 'print(self.item') # error in command
Radiobutton('a;b', 'print(self.item)') # correct
app.run()
radio5.py
Checkbutton
A checkbutton is like a regular button, with a label and a callback function, but it also holds and displays a binary
state.
The Checkbutton object has the following attributes:
• parent - the parent object
• text - the label to display
• command - the callback function
• variable - the variable holding the state value
• onvalue - the value when in the ON state
• offvalue - the value when in the OFF state
27
tk tutorial Documentation, Release 2020
We notice that the default offvalue is 0 and the default onvalue is 1. In our case:
• var0 toggles between 0 and 1
• var1 toggles between barely and 1
• var2 toggles between 0 and fluent
import tkinter as tk
root = tk.Tk()
var0 = tk.StringVar(value='1')
var1 = tk.StringVar(value='0')
var2 = tk.StringVar(value='0')
def cb():
print('--- languages ---')
print('English', var0.get())
print('German', var1.get())
print('French', var2.get())
root.mainloop()
check1.py
Now let us rewrite this program by using lists.
28 Chapter 4. Checkbutton
tk tutorial Documentation, Release 2020
import tkinter as tk
root = tk.Tk()
def cb():
print('--- languages ---')
for i, s in enumerate(texts):
print(s, vars[i].get())
root.mainloop()
check2.py
It’s time now to define a new and better Checkbutton class which can do everything in one line:
Checkbutton('English;German;French', 'print(self.selection)')
['French']
['German', 'French']
['English', 'German', 'French']
"""Create checkbuttons."""
from tklib import *
app = App()
Checkbutton('English;German;French', 'print(self.selection)')
app.run()
check3.py
Now let’s see how this class is defined
30 Chapter 4. Checkbutton
CHAPTER 5
entry0.py
Since these widgets are very similar, we treat them in the same section.
An entry widget presents the user an empty field where he can enter a text value.
Each ttk.Entry object has these options:
• parent - the parent object
• textvariable - the text variable to hold the entered string
• width - the numbers of characters
31
tk tutorial Documentation, Release 2020
import tkinter as tk
root = tk.Tk()
name = tk.StringVar()
tk.Label(text='Name').pack()
tk.Entry(root, textvariable=name, width=10).pack()
password = tk.StringVar()
tk.Label(text='Password').pack()
tk.Entry(root, textvariable=password, show='*').pack()
root.mainloop()
entry1.py
It’s time now to define a new and better Entry class which can do everything in one line:
The command function evaluates the expression entered and displays the result in the following label widget:
app.run()
entry2.py
Now let’s see how this class is defined
5.3 Combobox
A combobox combines an entry widget with a list of choices. The user can either select text from a drop-down menu
or write his own text.
The first combobox allows to also enter your own text, while the second one is restricted to chose an item from the
drop-down menu by setting state='readonly'.
Label('state=readonly')
day2 = tk.StringVar()
day2.set(days[1])
ttk.Combobox(App.stack[-1], textvariable=day2, values=days, state='readonly').grid()
app.run()
combo1.py
A combobox combines a list of choices with an entry. The user can select from the list, but he can also enter directly
a value.
app.run()
combo2.py
How is this new class defined ?
self.var = tk.StringVar()
self.var.set(values[val])
self.add_cmd(cmd)
self.bind('<<ComboboxSelected>>', self.cb)
5.6 Exemple
App.entry = Entry('value')
Combobox('dir(ttk)', dir(ttk), 'print(eval("ttk."+self.item))')
app.run()
combo3.py
def cb(e=None):
print(c1.var.get())
app.run()
combo4.py
5.8 Spinbox
A spinbox widget is an entry widget with built-in up and down buttons that are used to either modify a numeric value
or to select among a set of values. The widget implements all the features of the entry widget.
app = App('Spinbox')
var1 = tk.StringVar(value='10')
ttk.Spinbox(App.stack[-1], from_=5.0, to=100.0, increment=25, textvariable=var1).
˓→grid()
app.run()
spinbox1.py
5.8. Spinbox 37
tk tutorial Documentation, Release 2020
spinbox2.py
5.9 Scale
A scale widget provides a way for users to choose a numeric value through direct manipulation.
app = App('Scale')
Scale('Scale', 'print(self.var.get())', to=10, length=200)
Scale('from=-50, to=50', 'print(self.var.get())', from_=-50, to=50)
app.run()
scale2.py
The four classes Entry, Combobox, Spinbox and Scale have two common parts:
• adding an optional label in front of the widget
• adding a callback function
This two functions can be placed in a specal class called EntryMixin, which serves as second parent class for the 4
entry classes.
class EntryMixin:
"""Add label, widget and callback function."""
self.var = tk.StringVar()
self.var.set(values[val])
self.add_cmd(cmd)
self.bind('<<ComboboxSelected>>', self.cb)
self.var = tk.StringVar(value=val)
if len(values) > 1:
self['values'] = values
self.add_cmd(cmd)
self.add_cmd(cmd)
if isinstance(cmd, str):
(continues on next page)
43
tk tutorial Documentation, Release 2020
Basic widgets
In this section we are going to look in more detail at these basic widgets:
• Button
• Label
• Entry
• Frame
7.1 Button
Button()
Button('Print 123', 'print(123)', padding=10)
Button('Hello', 'print("Hello " * 3)', default='active')
The first button has the default text Button and does nothing.
The second button has a padding of 10 pixels and prints .!frame.!button2
The third button is active by default and prints:: Hello Hello Hello
45
tk tutorial Documentation, Release 2020
class Demo(App):
"""Create different buttons."""
def __init__(self):
super().__init__()
App.root.title('Button Demo')
Button()
Button('Print self', 'print(self)', padding=10)
Button('Hello', 'print("Hello " * 3)', default='active')
Demo().run()
button1.py
Demo().run()
button2.py
7.3 Fonts
class Demo(App):
def __init__(self):
super().__init__()
Demo().run()
font1.py
7.3. Fonts 47
tk tutorial Documentation, Release 2020
Labels can be displayed with an additional image. The image position can be:
• center
• left/right
• top/bottom
import os
from tklib import *
from PIL import Image, ImageTk
class Demo(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Label('Show images', font='Arial 24')
lb = Label()
App.img0 = Image.open('icons/bell.png')
App.img = ImageTk.PhotoImage(App.img0)
lb['image'] = App.img
L = 'text;image;center;top;left;bottom;right'.split(';')
i = 0
for l in L:
lb = Label(l, compound=l, image=App.img, padding=10)
lb.grid(column=i, row=1)
i += 1
Demo().run()
label1.py
class Demo(App):
def __init__(self):
super().__init__()
Label('Show images as labels', font='Arial 24')
dir = os.listdir('icons')
n, m = 2, 5
self.images = []
Frame()
for i in range(n):
for j in range(m):
k = m*i + j
label = dir[k]
path = 'icons/' + label
img0 = Image.open(path)
img = ImageTk.PhotoImage(img0)
self.images.append(img)
lb = Label(image=img, text=label, compound='top')
lb.grid(row=i, column=j)
Demo().run()
label2.py
class Demo(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Label('Show images as buttons', font='Arial 24')
dir = os.listdir('icons')
n, m = 2, 5
self.images = []
Frame()
for i in range(n):
for j in range(m):
k = m*i + j
label = dir[k]
path = 'icons/' + label
img0 = Image.open(path)
img = ImageTk.PhotoImage(img0)
self.images.append(img)
lb = Button(image=img, text=label, compound='top')
lb.grid(row=i, column=j)
if __name__ == '__main__':
Demo().run()
label3.py
class Demo(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Label('Show images in a treeview', font='Arial 24')
dir = os.listdir('icons')
self.tree = Treeview(height=20)
self.images = []
(continues on next page)
Demo().run()
label4.py
"""Embedded frames."""
from tklib import *
class Demo(App):
def __init__(self):
super().__init__()
Label('Embedded frames', font='Arial 24')
Demo().run()
frame1.py
"""Speparate frames."""
from tklib import *
class Demo(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Frame()
Button()
Entry()
Frame()
Button()
Entry()
App.stack.pop()
App.stack.pop()
Button()
Frame()
Button()
Entry()
if __name__ == '__main__':
Demo().run()
frame2.py
Events
widget.bind(event, handler)
If an event matching the event pattern happens, the corresponing handler is called.
Here is an exemple which prints mouse Button and Motion events to the status bar:
class Demo(App):
def __init__(self):
super().__init__()
Label("Button and Motion events", font="Arial 24")
Label('Display the event in the status bar')
App.root.bind('<Button>', self.cb)
App.root.bind('<Motion>', self.cb)
55
tk tutorial Documentation, Release 2020
def cb(event):
"""Callback function."""
print(event)
app.root.bind('<Button>', cb)
app.root.bind('<Motion>', cb)
app.run()
event1.py
The following program sends Button and Mouse events to a Text widget, just by changing the callback function:
56 Chapter 8. Events
tk tutorial Documentation, Release 2020
class Demo(App):
def __init__(self):
super().__init__()
Label("Button and Motion events", font="Arial 24")
App.txt = Text(scroll='y')
App.root.bind('<Button>', self.cb)
App.root.bind('<Motion>', self.cb)
if __name__ == '__main__':
Demo().run()
event2.py
App.root.bind('<Enter>', self.cb)
App.root.bind('<Leave>', self.cb)
App.root.bind('<Return>', self.cb)
App.root.bind('<Configure>', self.cb)
class Demo(App):
"""Write Enter, Leave and Return events to a Text widget."""
def __init__(self):
super().__init__()
Label("Enter, Leave and Return events", font="Arial 24")
App.txt = Text()
App.txt.grid(sticky='nswe')
App.root.bind('<Enter>', self.cb)
App.root.bind('<Leave>', self.cb)
App.root.bind('<Return>', self.cb)
App.root.bind('<Configure>', self.cb)
58 Chapter 8. Events
tk tutorial Documentation, Release 2020
if __name__ == '__main__':
Demo().run()
event3.py
Specific keyboard events can be bound to a specific widget and trigger a callback function. In the example below
we bind different keys to the root widget in order to call a callback function. The callback function inserts the event
despcriptor or a short text into a Text widget.
• <Key> - any key
• a - a lower-case a (or any other letter)
• A - an upper-case A
• <Return> - the Return key
• <Escape> - the Escape key
• <Tab> - the Tab key
Modifier keys can also bind to a callback function. They work equally for the left and the right keys.
• <Shift_L> for the Shift keys
• <Control_L> for the Control keys
• <Alt_L> for the Alt keys
• <Meta_L> for the Command key (on the Mac)
• <Super_L> for the Fn key (on the Mac)
Finally we configure the BackSpace key to clear the screen:
# keyboard bindings
import tkinter as tk
def cb(event):
text.insert('end', str(event) + '\n')
root = tk.Tk()
text = tk.Text(root)
text.grid()
root.bind('<Key>', cb)
root.bind('a', lambda e: cb('a'))
root.bind('A', lambda e: cb('A'))
root.bind('<Return>', lambda e: cb('Return'))
root.bind('<Escape>', lambda e: cb('Escape'))
root.bind('<Tab>', lambda e: cb('Tab'))
root.bind('<space>', lambda e: cb('space'))
root.bind('<F1>', lambda e: cb('F1'))
60 Chapter 8. Events
tk tutorial Documentation, Release 2020
# clear screen
root.bind('<BackSpace>', lambda e: text.delete('1.0', 'end'))
root.mainloop()
event4.py
62 Chapter 8. Events
CHAPTER 9
Listbox
A listbox displays a list of single-line text items, and allows users to browse through the list, and selecting one or more
items.
The old way of creating a listbox, was to create an empty listbox widget and then to insert item by item into the listbox.
The listbox methods insert and delete allow to add or remove items a specific position. The label tk.END is
used to add items to the end of the listbox. Here three items are added at the top and one item is removed:
To insert multiple items of a list one can iterate through the list:
63
tk tutorial Documentation, Release 2020
lb.insert(tk.END, *items)
root = tk.Tk()
lb = tk.Listbox(root)
lb.grid()
items = dir(tk)
for item in items:
lb.insert(tk.END, item)
lb.insert(tk.END, *items)
root.mainloop()
lb1.py
The new and much simpler way of handling the listbox content is to use the listvariable argument which must be set
to a StringVar object. The program below displays the attributes of the Tk module as a list:
64 Chapter 9. Listbox
tk tutorial Documentation, Release 2020
items = dir(tk)
var = tk.StringVar()
var.set(items)
tk.Listbox(root, listvariable=var).grid()
root = tk.Tk()
items = dir(tk)
var = tk.StringVar()
var.set(items)
tk.Listbox(root, listvariable=var).grid()
root.mainloop()
lb2.py
root = tk.Tk()
var = tk.StringVar(value=dir(tk))
root.mainloop()
root.mainloop()
lb3.py
When the user selects an item, either with a mouse click or with the arrow keys, a virtual <ListboxSelect> event is
generated. You can bind to it to a callback function:
lb.bind('<<ListboxSelect>>', cb)
The callback function prints the event descriptor and the current selection as an index list to a label:
def cb(event):
label['text'] = str(event) + '\n' + str(lb.curselection())
66 Chapter 9. Listbox
tk tutorial Documentation, Release 2020
def cb(event):
label['text'] = str(event) + '\n' + str(lb.curselection())
root = tk.Tk()
var = tk.StringVar(value=dir(tk))
label = tk.Label(root)
label.grid()
root.mainloop()
lb4.py
In the following example we display the selected listbox item in an entry field. The entry field can be edited and hitting
the return key writes the new item value to the listbox. The screen capture below shows how ANCHOR had been
changed to ANCHOR_function.
def select(event):
i = lb.curselection()[0]
item.set(items[i])
def update(event):
i = lb.curselection()[0]
items[i] = item.get()
var.set(items)
root = tk.Tk()
items = dir(tk)
var = tk.StringVar(value=items)
lb = tk.Listbox(root, listvariable=var)
lb.grid()
lb.bind('<<ListboxSelect>>', select)
item = tk.StringVar()
entry = tk.Entry(root, textvariable=item, width=20)
entry.grid()
entry.bind('<Return>', update)
68 Chapter 9. Listbox
tk tutorial Documentation, Release 2020
lb5.py
listbox4.py
class Browser(Listbox):
def cb(self, event):
(continues on next page)
70 Chapter 9. Listbox
tk tutorial Documentation, Release 2020
class Demo(App):
def __init__(self):
super().__init__()
Label('Regular expressions', font='Arial 18')
Label('Enter a Perl-style regular expression')
App.re = Entry('regex')
App.re.bind('<Key>', self.recompile)
App.status = Label('Status')
Checkbutton('IGNORECASE;MULITILINE;DOTALL;VERBOSE')
App.str = Text(height=10)
App.str.bind('<Key>', self.reevaluate)
App.str.tag_configure("hit", background="yellow")
Label('Groups')
App.groups = Listbox()
btags = App.re.bindtags()
App.re.bindtags(btags[1:] + btags[:1])
btags = App.str.bindtags()
App.str.bindtags(btags[1:] + btags[:1])
self.compiled = None
nmatches = 0
while last <= len(text):
m = self.compiled.search(text, last)
if m is None:
break
first, last = m.span()
if last == first:
last = first+1
tag = "hit0"
else:
tag = "hit"
pfirst = "1.0 + %d chars" % first
plast = "1.0 + %d chars" % last
self.str.tag_add(tag, pfirst, plast)
if nmatches == 0:
self.str.yview_pickplace(pfirst)
groups = list(m.groups())
groups.insert(0, m.group())
for i in range(len(groups)):
g = "%2d: %r" % (i, groups[i])
App.groups.insert(END, g)
nmatches = nmatches + 1
if self.showvar.get() == "first":
break
if nmatches == 0:
self.status.config(text="(no match)",
background="yellow")
else:
self.status.config(text="")
Demo().run()
re1.py
72 Chapter 9. Listbox
tk tutorial Documentation, Release 2020
app.run()
re2.py
74 Chapter 9. Listbox
CHAPTER 10
Menu
This section describes how to create menubars and popup menus. Menus are widgets as well. We add the following
code to the App() class. Creating the menu bar:
menubar = tk.Menu(root)
root['menu'] = menubar
Placing the menu bar on a menus stack for accessing to the menu items later on.
• menus[0] is always the menu bar
• menus[1] is the first menu item created
• menus[-1] is the last menu item created
This initializes the menu stack:
menus = [menubar]
class Menu(tk.Menu):
"""Add a Menu() node to which a menu Item() can be attached."""
def __init__(self, label, id=0, **kwargs):
super(Menu, self).__init__(App.menus[0], **kwargs)
App.menus[id].add_cascade(menu=self, label=label)
App.menus.append(self)
75
tk tutorial Documentation, Release 2020
class Demo(App):
def __init__(self):
super().__init__()
Label("Menu bar without items", font="Arial 24")
Demo().run()
menu1.py
To add items to a menu bar, we first call Menu() and then Item() for each menu item to add to the menu: The Item
object has the following parameters:
• label: the text to appear in the menu item
• cmd: an executable string
• acc (accelerator): a shortcut composed of Control/Command - (hyphen) and a lower-case letter
The following exemple adds 6 items to the 6 menus previously created:
class Demo(App):
def __init__(self):
super().__init__()
Label("Menu bar with items", font="Arial 24")
Demo().run()
menu2.py
Each new menu can be attached to the menu bar (default) or can be attached to an existing menu. The parameter id.
The following code adds a new submenu at the end of the previously created menu. Then it adds 3 subitems, and
finally an item which is directly attached to the parent Menu():
class Menu(tk.Menu):
"""Add a Menu() node to which a menu Item() can be attached."""
if label == '-':
App.menus[id].add_separator()
elif label[0] == '*':
App.menus[id].add_checkbutton(
label=label[1:], command=cmd, accelerator=acc, **kwargs)
elif label[0] == '#':
App.menus[id].add_radiobutton(
label=label[1:], command=cmd, accelerator=acc, **kwargs)
else:
App.menus[id].add_command(
label=label, command=cmd, accelerator=acc, **kwargs)
class Demo(App):
def __init__(self):
super().__init__()
Label("Insert items at specific index.", font="Arial 24")
Menu('Menu')
for i in range(5):
Item('Item {}'.format(i), cmd=lambda : print(i), acc='Command-'+str(i))
Menu('Window', name='window')
Menu('Help', name='help')
Demo().run()
class Demo(App):
def __init__(self):
super().__init__()
Label("Checkbuttones and radiobuttons.", font="Arial 24")
Menu('Checkbutton')
for i in range(5):
Item('*Item {}'.format(i))
Menu('Radiobutton')
radio = tk.StringVar()
for i in range(5):
Item('#Item {}'.format(i), variable=radio)
Menu('Help', name='help')
Demo().run()
The Menu.post() method is used to open the context menu at the current cursor position:
class ContextMenu(tk.Menu):
def __init__(self, widget):
"""Create a context menu attached to a widget."""
super(ContextMenu, self).__init__(widget)
App.menus.append(self)
class Demo(App):
def __init__(self):
super().__init__()
l1 = Label("Context Menu", font="Arial 24")
l2 = Label("Context Menu 2", font="Arial 48")
ContextMenu(l1)
Item('Item 1', 'print(1)')
Item('Item 2', 'print(2)')
Item('Item 3', 'print(3)')
ContextMenu(l2)
for c in 'ABC':
Item('Item ' + c)
ContextMenu(App.root)
Item('Cut', 'print("Cut")')
Item('Copy', 'print("Copy")')
Demo().run()
menu5.py
Normally we build menus in order. We create a Menu() object, and then we add the Item() objects subsequently.
With the insert method it is possible to attach an item anywhere in the existing menu.
This inserts an new command at index=2:
class Demo(App):
def __init__(self):
super().__init__()
Label("Insert items at specific index.", font="Arial 24")
Menu('Menu')
for i in range(5):
Item('Item {}'.format(i), cmd=lambda : print(i), acc='Command-'+str(i))
Menu('Window', name='window')
Menu('Help', name='help')
Demo().run()
menu6.py
If no new menu is defined for a new window, the root menu will be used for the new window. If a new menu is added
after the window is created, this window will have it’s own menu. Whenever a window becomes active, it will display
it’s own menu bar.
This shows the creation of two new windows with their different menubars:
Window("Letters")
Button()
Entry()
Menu1()
Menu('Help', name='help')
Window("Numbers")
Entry()
Menu2()
def Menu1():
Menu('Letters')
for c in 'ABC':
Item('Item ' + c)
def Menu2():
Menu('Numbers')
for c in '123':
Item('Item ' + c)
class Demo(App):
# constructor
def __init__(self):
super().__init__()
Label("Different menus for each window.", font="Arial 24")
Menu1()
Menu2()
Window("Numbers")
Entry()
Menu2()
Demo().run()
menu7.py
The next example shows how to add widgets dynamically. The Widget menu contains specific widgets as items
which are added to the current window:
Menu('Widgets')
Item('Button', 'Button()', 'Command-b')
Item('Label', 'Label()', 'Command-l')
Item('Entry', 'Entry()', 'Command-e')
Item('Radiobutton', 'Radiobutton()', 'Command-r')
Item('Checkbutton', 'Checkbutton()', 'Command-k')
Item('Canvas', 'Canvas()', 'Command-c')
Item('Listbox', 'Listbox(height=5)', 'Command-i')
Item('Scale', 'Scale()', 'Command-s')
Item('Text', 'Text(width=30, height=5)', 'Command-t')
class Demo(App):
def __init__(self):
super().__init__()
(continues on next page)
Menu('Widgets')
Item('Button', 'Button()', 'Command-b')
Item('Label', 'Label()', 'Command-l')
Item('Entry', 'Entry()', 'Command-e')
Item('Radiobutton', 'Radiobutton()', 'Command-r')
Item('Checkbutton', 'Checkbutton()', 'Command-k')
Item('Canvas', 'Canvas()', 'Command-c')
Item('Listbox', 'Listbox(height=5)', 'Command-i')
Item('Scale', 'Scale()', 'Command-s')
Item('Text', 'Text(width=30, height=5)', 'Command-t')
Demo().run()
menu8.py
class Demo(App):
def __init__(self):
super().__init__()
Label("Insert widgets via the menu.", font="Arial 24")
(continues on next page)
ContextMenu(text)
Item('Item 1', 'print(1)')
Item('Item 2', 'print(2)')
Item('Item 3', 'print(3)')
Demo().run()
menu9.py
Canvas
The Canvas widget can be used to draw lines, shapes, and text to create complex drawings and graphs. The origin (0,
0) of the canvas is in the top left corner. It has the keyword options:
• background = background color
• borderwidth
• height
• width
87
tk tutorial Documentation, Release 2020
app.run()
canvas1.py
app.run()
canvas2.py
Small ovals can be used to paint with the mouse, by binding a callback function to the mouse movement.
class Demo(App):
def __init__(self):
super().__init__()
Label("Painting using ovals", font="Arial 24")
self.c = Canvas(width=600, height=300, background='lightblue')
self.c.bind('<B1-Motion>', self.paint)
Demo().run()
canvas3.py
11.4 Polygons
We can add our own methods to the Canvas class. For example we can define a method to add a polygon.
def polygon(self, x0, y0, r, n, **kwargs):
points = []
for i in range(n):
a = 2 * math.pi * i / n
x = x0 + math.sin(a) * r
y = y0 + math.cos(a) * r
(continues on next page)
app.run()
canvas4.py
w, h = 600, 300
c = Canvas(width=w, height=h, background='lightblue')
for i in range(50):
x = random.randint(0, w)
y = random.randint(0, h)
r = random.randint(10, 100)
c.create_oval(x, y, x+r, y+r)
app.run()
canvas5.py
"""Canvas config."""
from tklib import *
class Demo(App):
def __init__(self):
super().__init__()
Label("Canvas configuration", font="Arial 24")
Spinbox('borderwidth', 'App.c.config(borderwidth=self.var.get())')
(continues on next page)
Button('Config', 'print(App.c.config())')
App.c = Canvas()
Demo().run()
canvas6.py
class Option:
def __init__(self, widget):
self.w = widget
tree = Treeview(columns=(0))
tree.column(0, width=150)
tree.heading(0, text='Value')
tree.grid(row=0, column=2)
d = self.w.config()
print(d)
for (k, v) in d.items():
if len(v)>2:
tree.insert('', 'end', text=k, values=v[-1])
class Demo(App):
def __init__(self):
super().__init__()
Label("Canvas configuration", font="Arial 24")
App.stack[-1]=Frame()
App.c = Canvas(background='lightblue',
(continues on next page)
tree = Treeview(columns=(0))
tree.column(0, width=150)
tree.heading(0, text='Value')
tree.grid(row=0, column=1)
Option(App.c)
Demo().run()
canvas7.py
class Demo(App):
def __init__(self):
super().__init__()
Label("Drawing shapes", font="Arial 24")
Combobox('fill', 'black;red;green;blue;orange;cyan',
'App.c.itemconfig(App.c.id, fill=self.val.get())')
Spinbox('width', 'App.c.itemconfig(App.c.id, width=self.val.get())', from_=1,
˓→to=20)
Button('Delete', 'App.c.delete(App.c.id)')
Button('Delete All', 'App.c.delete("all")')
Combobox('type', 'arc;line;rectangle;oval',
'App.c.itemconfig(App.c.id, fill=self.val.get())')
Button('Config', 'print(App.c.itemconfig(1))')
App.c = Canvas()
print(vars(App.c))
print()
print(dir(App.c))
Demo().run()
canvas9.py
In order to draw with the mouse we have to add two bindings to the canvas:
• <Button-1> to initiate the drawing, calling the start() method
• <B1_Motion> to update the current drawing, calling the move() method
class Canvas(tk.Canvas):
"""Define a canvas with line drawing"""
app.run()
draw1.py
Scrollbar
"""Display scrollbars."""
from tklib import *
class Demo(App):
(continues on next page)
99
tk tutorial Documentation, Release 2020
ttk.Scrollbar(App.stack[-1], orient=tk.HORIZONTAL).grid()
ttk.Scrollbar(App.stack[-1], orient=tk.VERTICAL).grid()
Demo().run()
scrollbar1.py
class Demo(App):
def __init__(self):
super().__init__()
Label("Listbox with scrollbars", font="Arial 18")
lb = Listbox(list(range(100)))
sb = ttk.Scrollbar(App.stack[-1])
sb.grid(row=1, column=1, sticky='ns')
lb.config(yscrollcommand=sb.set)
sb.config(command=lb.yview)
Demo().run()
scrollbar2.py
class Demo(App):
def __init__(self):
super().__init__()
Label('Scrollable text', font='Arial 24')
Label("No scrollbars")
Text(text, height=5, wrap='none')
Label("X scrollbars")
Text(text, height=5, scroll='x', wrap='none')
Label("Y scrollbars")
(continues on next page)
Label("XY scrollbars")
Text(text, height=5, scroll='xy', wrap='none')
Demo().run()
scrollbar3.py
class Canvas(tk.Canvas):
def __init__(self, scroll='', scrollregion=(0, 0, 1000, 1000), **kwargs):
self = Scrollable(tk.Canvas, scroll=scroll, scrollregion=scrollregion,
˓→**kwargs)
Label('scroll=')
Canvas(height=h)
Label('scroll=x')
Canvas(height=h, scroll='x')
Label('scroll=y')
Canvas(height=h, scroll='y')
Label('scroll=xy')
Canvas(height=h, scroll='xy')
Demo().run()
scrollbar5.py
12.4 Sources
• http://effbot.org/zone/tkinter-scrollbar-patterns.htm
Text
The Text widget displays multi-line text and is user editable. Its size is given in lines and characters.
105
tk tutorial Documentation, Release 2020
"""Display tk Text."""
from tklib import *
class Demo(App):
def __init__(self):
super().__init__()
Label("Text widget", font="Arial 18")
Label('2 lines')
Text('Initial text...', height=2, width=50)
Label('10 lines')
text = Text(height=10, width=50)
text.insert('1.0', 'Add some text at the beginning of the Text widget.')
Demo().run()
text1.py
Text can be edited as usual. Cut, copy, paste is possible. The cursor can be placed with the mouse. Mouse and and
arrow key selection are both possible.
"""Display tk Text."""
from tklib import *
class Demo(App):
def __init__(self):
super().__init__()
Label("Text widget", font="Arial 18")
Spinbox('width', 'App.text["width"]=self.val.get()').set(80)
(continues on next page)
Demo().run()
text2.py
class Demo(App):
def __init__(self):
super().__init__()
Label("Undo and Redo", font="Arial 18")
Button('Selection')
Button('Edit Undo', 'App.text.edit_undo()')
Button('Edit Redo', 'App.text.edit_redo()')
Inspector(App.text, height=20)
Demo().run()
text3.py
str = """Up until now, we've just dealt with plain text.
Now it's time to look at how to add special formatting, such as bold, italic,
and much more. Tk's text widget implements these using a feature called tags.
Tags are objects associated with the text widget.
Each tag is referred to via a name.
Each tag can have a number of different configuration options;
these are things like fonts, colors, etc. that will be used to format text.
Though tags are objects having state, they don't need to be explicitly created;
they'll be automatically created the first time the tag name is used.
"""
class Demo(App):
def __init__(self):
super().__init__()
(continues on next page)
b = Button('Popup Menu')
App.m = ContextMenu(b)
Item('Item 1', 'print(1)')
Item('Item 2', 'print(2)')
Item('Item 3', 'print(3)')
Demo().run()
text4.py
str = """Up until now, we've just dealt with plain text.
Now it's time to look at how to add special formatting, such as bold, italic,
strikethrough, background colors, font sizes, and much more. Tk's text widget
implements these using a feature called tags.
Tags are objects associated with the text widget.
Each tag is referred to via a name chosen by the programmer.
"""
def highlight():
sel = App.text.tag_ranges('sel')
if len(sel) > 0:
App.text.tag_add('highlight', *sel)
def big():
sel = App.text.tag_ranges('sel')
if len(sel) > 0:
App.text.tag_add('big', *sel)
class Demo(App):
def __init__(self):
super().__init__()
Label("Formatting with tags", font="Arial 18")
Button('Highlight', highlight)
Button('Big', big)
Demo().run()
text5.py
Widgets can be placed inside text. They move with the text.
def hello():
print('hello')
class Demo(App):
def __init__(self):
super().__init__()
Label("Widgets inside Text", font="Arial 18")
Demo().run()
text6.py
Text can be searched. Regular expressions can be used. The exemple below shows the search for vowels which are
highlighted in yellow.
"""Search in text."""
from tklib import *
str = """Up until now, we've just dealt with plain text.
Now it's time to look at how to add special formatting, such as bold, italic,
strikethrough, background colors, font sizes, and much more. Tk's text widget
implements these using a feature called tags.
"""
def highlight():
sel = App.text.tag_ranges('sel')
if len(sel) > 0:
App.text.tag_add('highlight', *sel)
def search(event=None):
App.text.tag_remove("highlight", "1.0", "end")
start = 1.0
while True:
pattern = App.re.val.get()
pos = App.text.search(pattern, start, stopindex='end', regexp=True)
if not pos:
break
print(pos)
App.text.tag_add('highlight', pos, pos+'+1c')
start = pos + '+1c'
class Demo(App):
def __init__(self):
super().__init__()
Label("Search with regexp", font="Arial 18")
Demo().run()
text7.py
"""Help browser."""
from tklib import *
class Demo(App):
def __init__(self):
super().__init__()
Label("Help display", font="Arial 24")
str = tk.__doc__
App.text = Text(str, width=70)
Demo().run()
text8.py
Treeview
A treeview widget can display a hierarchy of items. The items are organized in the form of a tree. The parent node is
'' and is not displayed. Within a node the items are indexed: 0 being the first item, 'end' representing the position
after the last item.
To insert an item to t treeview use the function:
The first example creates a treeview, adds an item at position 0, and another item at position end. The id of the third
item is assigned to a local variable in order to use it as a node for creating to sub-items.
115
tk tutorial Documentation, Release 2020
tree = ttk.Treeview(App.stack[-1])
tree.grid()
tree.insert('', 0, text='Item 1')
tree.insert('', 'end', text='Item 2')
tree0.py
The width, alignment and label of a column can further be specified. To insert values to the new columns use the
method set:
tree = ttk.Treeview(App.stack[-1])
(continues on next page)
app.run()
tree1_col.py
Like the text and canvas widgets, the Treeview widget uses tags to modify the appearance of lines. Tags are simply
a list of strings, such as:
tree.tag_configure('bg', background='yellow')
tree.tag_configure('fg', foreground='red')
tree = ttk.Treeview(App.stack[-1])
tree.grid()
tree.tag_configure('bg', background='yellow')
tree.tag_configure('fg', foreground='red')
app.run()
tree1_tag.py
Tags are also used to bind lines to events. This adds a callback to the button click:
In the callback function cb we print the event, the selection and the focus:
def cb(event):
print(event, tree.selection(), tree.focus())
def cb(event):
print(event, tree.selection(), tree.focus())
tree = ttk.Treeview(App.stack[-1])
tree.grid()
app.run()
tree1_bind.py
app = App('Treeview')
items = dir(tk)
tree = Treeview()
tree['columns'] = ('type', 'value')
tree.column('type', width=100)
tree.heading('type', text='Type')
tree.heading('value', text='Value')
items = dir()
Treeview(items).grid(row=0, column=1)
app.run()
tree2.py
"""Display a 2D table."""
n, m = 40, 10
table = []
for i in range(n):
line = []
for j in range(m):
line.append(random.randint(0, 999))
table.append(line)
class Demo(App):
def __init__(self):
super().__init__()
Label('Display a 2D table', font='Arial 24')
Label('Click on header to sort')
Combobox('A;B;C')
tree = Treeview()
for i in range(n):
tree.insert('', 'end', text=table[i][0], values=table[i][1:])
tree['columns'] = list(range(m-1))
headings=list('ABCDEFGHI')
for j in range(m-1):
tree.column(j, width=50, anchor='e')
tree.heading(j, text=headings[j])
if __name__ == '__main__':
Demo().run()
tree4.py
class Demo(App):
def __init__(self):
super().__init__()
Label('Insert items to the tree', font='Arial 24')
App.tree = Treeview()
L = 'Hello;Dolly;How;Are;You'.split(';')
for item in L:
App.tree.insert('', 'end', text=item)
(continues on next page)
if __name__ == '__main__':
Demo().run()
tree5.py
class Demo(App):
def __init__(self):
super().__init__()
Label('Columns', font='Arial 24')
App.tree = Treeview()
# App.tree['columns'] = ('size', 'date', 'type')
App.tree['columns'] = range(3)
(continues on next page)
for i in range(2):
App.tree.column(i, width=100, anchor='w')
App.tree.heading(i, text='Heading' + str(i))
L = 'Hello;Dolly;How;Are;You'.split(';')
for item in L:
App.tree.insert('', 'end', text=item)
if __name__ == '__main__':
Demo().run()
tree6.py
class Demo(App):
def __init__(self):
super().__init__()
Label('Customizing the Treeview widget', font='Arial 24')
App.tree = Treeview()
App.tree['columns'] = range(3)
for i in range(2):
App.tree.column(i, width=100, anchor='w')
App.tree.heading(i, text='Heading' + str(i))
L = 'Hello;Dolly;How;Are;You'.split(';')
for item in L:
App.tree.insert('', 'end', text=item)
if __name__ == '__main__':
Demo().run()
tree7.py
Windows
In this section we present how to create new windows and how to open dialog windows.
To create a new window we define a new Window class which instantiates the Toplevel class:
class Window():
"""Create a new window."""
def __init__(self, title='Window'):
top = tk.Toplevel(App.root)
top.title(title)
frame = ttk.Frame(top, width=300, height=200, padding=(5, 10))
frame.grid()
App.stack.append(frame)
top = tk.Toplevel(App.root)
top.title(title)
Then we add a themed frame widget in order to get the theme’s background color, add the geometry manager (grid)
and place the frame on the widget stack, so new widgets are added to the new window:
127
tk tutorial Documentation, Release 2020
App.stack.append(frame)
App.win = top
App.menus = [tk.Menu(App.win)]
App.win['menu'] = App.menus[0]
The following example adds two more windows besides the root window. Each one can be closed individually, but
only if the root window is closed, the application ends:
Window('Text')
Text(height=10, width=40)
Window('Canvas')
Canvas()
class Demo(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
App.root.title('Windows and dialogs')
Window('Text')
Text(height=10, width=40)
Window('Canvas')
Canvas()
Demo().run()
window1.py
The buttons have the following functions:
• New Window creates a new window
• Print window geometry prints the window placement (191x175+47+51)
• Print window title prints the window title (Window and dialogs)
• Resize H allows for only horizontal resizing
• Resize V allows for only vertical resizing
• Iconify iconifies the window
"""Standard dialogs."""
from tklib import *
from tkinter import filedialog, colorchooser
class Demo(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
App.root.title('Windows and dialogs')
Label('Standard Dialogs', font='Arial 24')
Demo().run()
window2.py
Pressing the Open. . . button opens a standard open file dialog and returns a path or an empty string (if cancelled).
"""Standard dialogs."""
from tklib import *
app.run()
dialog1.py
Demo().run()
window3.py
The following demo program shows how to insert buttons, labels and separators.
"""Separators."""
from tklib import *
class Demo(App):
def __init__(self, **kwargs):
(continues on next page)
Demo().run()
window4.py
The Labelframe widget is a frame used for grouping widgets, but has a label attached to it
"""Add Labelframes."""
from tklib import *
class Demo(App):
(continues on next page)
App.stack.pop()
Frame()
Button()
Entry()
Demo().run()
window5.py
The Panedwindow widget creates a slider and allows to change the width or hight between two or more widgets.
"""Paned windows."""
from tklib import *
class Demo(App):
(continues on next page)
p = Panedwindow(orient='horizontal')
print(p)
f1 = Canvas(background='pink')
f2 = Canvas(background='lightblue')
p.add(f1)
p.add(f2)
App.stack.pop()
Label('Another paned window')
p2 = Panedwindow(orient='horizontal')
print(p2)
p2.add(Canvas(background='yellow'))
p2.add(Canvas(background='lightgreen'))
p2.add(Canvas(background='orange'))
Demo().run()
window6.py
"""Tabbed notebooks."""
from tklib import *
class Demo(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Label('Tabbed Notebooks', font='Arial 24')
Button()
Notebook()
Frame(nb='Tab 1')
Button()
Frame(nb='Tab 2')
Entry()
Frame(nb='Tab 3')
Canvas(height=100)
App.stack.pop()
Notebook()
(continues on next page)
Demo().run()
window7.py
Demo().run()
window8.py
Time
In this section we are going to deal with time. The goal is to build four simple applications
• clock
• timer
• alarm
• chronometer
16.1 Clock
139
tk tutorial Documentation, Release 2020
class Clock(Window):
def __init__(self):
super(Clock, self).__init__('Clock')
self.lb = Label('hh:mm:ss', font='Arial 100')
top = self.lb.winfo_toplevel()
top.resizable(width=False, height=False)
self.cb()
d = time.strftime('%X %x %Z')
self.status['text'] = d
self.lb.after(1000, self.cb)
class Demo(App):
def __init__(self):
super().__init__()
Button('New Clock', Clock)
Clock()
if __name__ == '__main__':
Demo().run()
time1.py
16.2 Timer
Or a different layout.
class Clock(Window):
def __init__(self):
super(Clock, self).__init__('Clock')
self.lb = Label('hh:mm:ss', font='Arial 100')
top = self.lb.winfo_toplevel()
top.resizable(width=False, height=False)
self.cb()
d = time.strftime('%X %x %Z')
self.status['text'] = d
self.lb.after(1000, self.cb)
class Timer(Window):
def __init__(self):
super(Timer, self).__init__('Timer')
self.lb = Label('hh:mm:ss', font='Arial 100')
self.lb.grid(columnspan=4)
Button('Min').grid(row=1, column=0)
Button('Sec').grid(row=1, column=1)
Button('Start').grid(row=1, column=2)
Button('Reset').grid(row=1, column=3)
self.cb()
d = time.strftime('%X %x %Z')
self.status['text'] = d
self.lb.after(1000, self.cb)
(continues on next page)
class Demo(App):
def __init__(self):
super().__init__()
Button('New Clock', Clock)
Button('New Timer', Timer)
if __name__ == '__main__':
Demo().run()
time2.py
Applications
17.1 Calculator
App.lb = Label('0.0')
App.lb.grid(columnspan=4)
Button('AC', ).grid(row=1)
Button('±').grid(row=1, column=1)
Button('%').grid(row=1, column=2)
Button(':').grid(row=1, column=3)
143
tk tutorial Documentation, Release 2020
class Demo(App):
def __init__(self):
super().__init__()
App.lb = Label('0.0')
App.lb.grid(columnspan=4)
Button('AC', ).grid(row=1)
Button('±').grid(row=1, column=1)
Button('%').grid(row=1, column=2)
Button(':').grid(row=1, column=3)
Button('7').grid(row=2, column=0)
Button('8').grid(row=2, column=1)
Button('9').grid(row=2, column=2)
Button('x').grid(row=2, column=3)
Button('4').grid(row=3, column=0)
Button('5').grid(row=3, column=1)
Button('6').grid(row=3, column=2)
Button('-').grid(row=3, column=3)
Button('1').grid(row=4, column=0)
Button('2').grid(row=4, column=1)
Button('3').grid(row=4, column=2)
Button('+').grid(row=4, column=3)
if __name__ == '__main__':
Demo().run()
calc1.py
Then we are going to add callback functions to the keys:
class Demo(App):
def __init__(self):
super().__init__()
s = ttk.Style()
s.configure('TButton', font='Arial 18', padding=5)
Button('x').grid(row=2, column=3)
Button('-').grid(row=3, column=3)
(continues on next page)
Button('+').grid(row=4, column=3)
if __name__ == '__main__':
Demo().run()
calc2.py
It turns out that it is simpler to place the calculator logic into a separate function, based on a single character:
self.lb['text'] = self.val
class Demo(App):
def __init__(self):
super().__init__()
s = ttk.Style()
s.configure('TButton', font='Arial 18', padding=5)
self.val = 0
self.pos = 0
self.val2 = 0
App.root.bind('<Key>', self.cb)
self.lb['text'] = self.val
if __name__ == '__main__':
Demo().run()
calc3.py
And finally we put everything together. New Calculator instances can be created via a button press or via a menu.
class Calculator():
def __init__(self):
self.win = Window('Calculator')
s = ttk.Style()
s.configure('TButton', font='Arial 18', padding=5)
self.win.top.bind('<Key>', self.cb)
self.lb['text'] = self.val
class Demo(App):
def __init__(self):
super().__init__()
Button('New calculator', Calculator)
Menu('App')
Item('Calculator', Calculator)
if __name__ == '__main__':
Demo().run()
calc4.py
• genindex
• modindex
• search
151