Skip to content

Tkinter Module/Library

Standard Imports

Python
from tkinter import *  # import Python Tk Binding
from tkinter import ttk  # import Themed Widgets

GEOMETRY MANAGEMENT

Putting widgets on screen
master widget → top-level window, frame
slave widget → widgets contained in master widget
geometry managers determine size and oder widget drawing properties

EVENT HANDLING

event loop receives events from the OS
customizable events provide a callback as a widget configuration

Python
widget.bind('event', function)  # method to capture any event and than execute an arbitrary piece of code (generally a function or lambda)

VIRTUAL EVENT → hig level event generated by widget (listed in widget docs)

WIDGETS

Widgets are objects and all things on screen. All widgets are children of a window.

Python
widget_name = tk_object(parent_window)  # widget is inserted into widget hierarchy

FRAME WIDGET

Displays a single rectangle, used as container for other widgets

Python
1
2
3
frame = ttk.Frame(parent, width=None, height=None, borderwidth=num:int)
# BORDERWIDTH: sets frame border width (default: 0)
# width, height MUST be specified if frame is empty, otherwise determined by parent geometry manager

FRAME PADDING

Extra space inside widget (margin).

Python
1
2
3
4
5
6
frame['padding'] = num  # same padding for every border
frame['padding'] = (horizontal, vertical)  # set horizontal THEN vertical padding
frame['padding'] = (left, top, right, bottom)  # set left, top, right, bottom padding

# RELIEF: set border style, [flat (default), raised, sunken, solid, ridge, groove]
frame['relief'] = border_style

LABEL WIDGET

Display text or image without interactivity.

Python
label = ttk.Label(parent, text='label text')

DEFINING UPDATING LABEL

Python
1
2
3
var = StringVar()  # variable containing text, watches for changes. Use get, set methods to interact with the value
label['textvariable'] = var  # attach var to label (only of type StringVar)
var.set("new text label")  #  change label text

DISPLAY IMAGES (2 steps)

Python
image = PhotoImage(file='filename')  # create image object
label['image'] = image  # use image config

DISPLAY IMAGE AND-OR TEXT

Python
label['compound'] = value

Compound value:

  • none ../img if present, text otherwise)
  • text (text only)
  • image (image only)
  • center (text in center of image)
  • top (image above text), left, bottom, right

LAYOUT

Specifies edge or corner that the label is attached.

Python
label['anchor'] = compass_direction  #compass_direction: n, ne, e, se, s, sw, w, nw, center

MULTI-LINE TEXT WRAP

Python
# use \n for multi line text
label['wraplength'] = size  # max line length

CONTROL TEXT JUSTIFICATION

Python
1
2
3
4
5
label['justify'] = value  #value: left, center, right

label['relief'] = label_style
label['foreground'] = color  # color passed with name or HEX RGB codes
label['background'] = color  # color passed with name or HEX RGB codes

FONT STYLE (use with caution)

Python
# used outside style option
label['font'] = font

Fonts:

  • TkDefaultFont -- default for all GUI items
  • TkTextFont -- used for entry widgets, listboxes, etc
  • TkFixedFont -- standard fixed-width font
  • TkMenuFont -- used for menu items
  • TkHeadingFont -- for column headings in lists and tables
  • TkCaptionFont -- for window and dialog caption bars
  • TkSmallCaptionFont -- smaller caption for subwindows or tool dialogs
  • TkIconFont -- for icon caption
  • TkTooltipFont -- for tooltips

BUTTON

Press to perform some action

Python
button = ttk.Button(parent, text='button_text', command=action_performed)

TEXT or IMAGE

Python
button['text/textvariable'], button['image'], button['compound']

BUTTON INVOCATION

Python
button.invoke()  # button activation in the program

BUTTON STATE

Activate or deactivate the widget.

Python
1
2
3
4
5
6
button.state(['disabled'])            # set the disabled flag, disabling the button
button.state(['!disabled'])           # clear the disabled flag
button.instate(['disabled'])          # return true if the button is disabled, else false
button.instate(['!disabled'])         # return true if the button is not disabled, else false
button.instate(['!disabled'], cmd)  # execute 'cmd' if the button is not disabled
# WIDGET STATE FLAGS: active, disabled, focus, pressed, selected, background, readonly, alternate, invalid

CHECKBUTTON

Button with binary value of some kind (e.g a toggle) and also invokes a command callback

Python
checkbutton_var = TkVarType
check = ttk.Checkbutton(parent, text='button text', command=action_performed, variable=checkbutton_var, onvalue=value_on, offvalue=value_off)

WIDGET VALUE

Variable option holds value of button, updated by widget toggle.
DEFAULT: 1 (while checked), 0 (while unchecked)
onvalue, offvalue are used to personalize checked and unchecked values
if linked variable is empty or different from on-off value the state flag is set to alternate
checkbutton won't set the linked variable (MUST be done in the program)

CONFIG OPTIONS

Python
1
2
3
4
5
check['text/textvariable']
check['image']
check['compound']
check.state(['flag'])
check.instate(['flag'])

RADIOBUTTON

Multiple-choice selection (good if options are few).

Python
#RADIOBUTTON CREATION (usually as a set)
radio_var = TkVarType
radio_1 = ttk.Radiobutton(parent, text='button text', variable=radio_var, value=button_1_value)
radio_2 = ttk.Radiobutton(parent, text='button text', variable=radio_var, value=button_2_value)
radio_3 = ttk.Radiobutton(parent, text='button text', variable=radio_var, value=button_3_value)
# if linked value does not exist flag state is alternate

# CONFIG OPTIONS
radio['text/textvariable']
radio['image']
radio['compound']
radio.state(['flag'])
radio.instate(['flag'])

ENTRY

Single line text field accepting a string.

Python
1
2
3
4
entry_var = StringVar()
entry = ttk.Entry(parent, textvariable=entry_var, width=char_num, show=symbol)
# SHOW: replaces the entry test with symbol, used for password
# entries don't have an associated label, needs a separate widget

CHANGE ENTRY VALUE

Python
1
2
3
entry.get()  # returns entry value
entry.delete(start, 'end')  # delete between two indices, 0-based
entry.insert(index, 'text value')  # insert new text at a given index

ENTRY CONFIG OPTIONS

Python
radio.state(['flag'])
radio.instate(['flag'])

COMBOBOX

Drop-down list of available options.

Python
1
2
3
4
5
6
7
combobox_var = StringVar()
combo = ttk.Combobox(parent, textvariable=combobox_var)
combobox.get()  # return combobox current value
combobox.set(value)  # set combobox new value
combobox.current()  # returns which item in the predefined values list is selected (0-based index of the provided list, -1 if not in the list)
#combobox will generate a bind-able <ComboboxSelected> virtual event whenever the value changes
combobox.bind('<<ComboboxSelected>>', function)

PREDEFINED VALUES

Python
1
2
3
combobox['values'] = (value_1, value_2, ...)  # provides a list of choose-able values
combobox.state(['readonly'])  # restricts choose-able values to those provided with 'values' config option
# SUGGESTION: call selection clear method on value change (on ComboboxSelected event) to avoid visual oddities

LISTBOX (Tk Classic)

Display list of single-line items, allows browsing and multiple selection (part og Tk classic, missing in themed Tk widgets).

Python
1
2
3
lstbx = Listbox(parent, height=num, listvariable=item_list:list)
# listvariable links a variable (MUST BE a list) to the listbox, each element is a item of the listbox
# manipulation of the list changes the listbox

SELECTING ITEMS

Python
1
2
3
4
5
6
lstbx['selectmode'] = mode  # MODE: browse (single selection), extended (multiple selection)
lstbx.curselection()  # returns list of indices of selected items
# on selection change: generate event <ListboxSelect>
# often each string in the program is associated with some other data item
# keep a second list, parallel to the list of strings displayed in the listbox, which will hold the associated objects
# (association by index with .curselection() or with a dict).

SCROLLBAR

Python
1
2
3
4
5
6
scroll = ttk.Scrollbar(parent, orient=direction, command=widget.view)
# ORIENT: VERTICAL, HORIZONTAL
# WIDGET.VIEW: .xview, .yview
# NEEDS ASSOCIATED WIDGET SCROLL CONFIG
widget.configure(xscrollcommand=scroll.set)
widget.configure(yscrollcommand=scroll.set)

SIZEGRIP

Box in right bottom of widget, allows resize.

Python
ttk.Sizegrip(parent).grid(column=999, row=999, sticky=(S, E))

TEXT (Tk Classic)

Area accepting multiple line of text.

Python
1
2
3
4
5
6
7
txt = Text(parent, width=num:int, height=num:int, wrap=flag)  # width is character num, height is row num
# FLAG: none (no wrapping), char (wrap at every character), word (wrap at word boundaries)
txt['state'] = flag  # FLAG: disabled, normal
# accepts commands xscrollcommand and yscrollcommandand and yview, xview methods
txt.see(line_num.char_num)  # ensure that given line is visible (line is 1-based, char is 0-based)
txt.get( index, string)   # insert string in pos index (index = line.char), 'end' is shortcut for end of text
txt.delete(start, end)  # delete range of text

PROGRESSBAR

Feedback about progress of lenghty operation.

Python
1
2
3
4
5
6
progbar = ttk.Progressbar(parent, orient=direction, length=num:int, value=num, maximum=num:float mode=mode)
# DIRECTION: VERTICAL, HORIZONTAL
# MODE: determinate (relative progress of completion), indeterminate (no estimate of completion)
# LENGTH: dimension in pixel
# VALUE: sets the progress, updates the bar as it changes
# MAXIMUM: total number of steps (DEFAULT: 100)

DETERMINATE PROGRESS

Python
progbar.step(amount)  # increment value of given amount (DEFAULT: 1.0)

INDETERMINATE PROGRESS

Python
progbar.start()  # starts progressbar
progbar.stop()  #stoops progressbar

SCALE

Provide a numeric value through direct manipulation.

Python
1
2
3
4
5
scale = ttk.Scale(parent, orient=DIR, length=num:int, from_=num:float, to=num:float, command=cmd)
# COMMAND: calls cmd at every scale change, appends current value to func call
scale['value']  # set or read current value
scale.set(value)  # set current value
scale.get()  # get current value

SPINBOX

Choose numbers. The spinbox choses item from a list, arrows permit cycling lits items.

Python
1
2
3
4
5
spinval = StringVar()
spin = Spinbox(parent, from_=num, to=num, textvariable=spinval, increment=num, value=lst, wrap=boolean)
# INCREMENT specifies increment\decrement by arrow button
# VALUE: list of items associated with the spinbox
# WRAP: boolean value determining if value should wrap around if beyond start-end value

GRID GEOMETRY MANAGER

Widgets are assigned a "column" number and a "row" number, which indicates their relative position to each other.
Column and row numbers must be integers, with the first column and row starting at 0.
Gaps in column and row numbers are handy to add more widgets in the middle of the user interface at a later time.
The width of each column (or height of each row) depends on the width or height of the widgets contained within the column or row.

Widgets can take up more than a single cell in the grid ("columnspan" and "rowspan" options).

LAYOUT WITHIN CELL

By default, if a cell is larger than the widget contained in it, the widget will be centered within it,
both horizontally and vertically, with the master's background showing in the empty space around it.
The "sticky" option can be used to change this default behavior.
The value of the "sticky" option is a string of 0 or more of the compass directions "nsew", specifying which edges of the cell the widget should be "stuck" to.
Specifying two opposite edges means that the widget will be stretched so it is stuck to both.
Specifying "nsew" it will stick to every side.

HANDLING RESIZE

Every column and row has a "weight" grid option associated with it, which tells it how much it should grow if there is extra room in the master to fill.
By default, the weight of each column or row is 0, meaning don't expand to fill space.
This is done using the "columnconfigure" and "rowconfigure" methods of grid.
Both "columnconfigure" and "rowconfigure" also take a "minsize" grid option, which specifies a minimum size.

PADDING

Normally, each column or row will be directly adjacent to the next, so that widgets will be right next to each other.
"padx" puts a bit of extra space to the left and right of the widget, while "pady" adds extra space top and bottom.
A single value for the option puts the same padding on both left and right (or top and bottom),
while a two-value list lets you put different amounts on left and right (or top and bottom).
To add padding around an entire row or column, the "columnconfigure" and "rowconfigure" methods accept a "pad" option.

Python
widget.grid(column=num, row=num, columnspan=num, rowspan=num, sticky=(), padx=num, pady=num)  # sticky: N, S, E, W
widget.columnconfigure(pad=num, weight=num)
widget.rowconfigure(pad=num, weight=num)

widget.grid_slaves()  # returns map, list of widgets inside a master
widget.grid_info()  # returns list of grid options
widget.grid_configure()  # change one or more option

widget.grid_forget(slaves)  # takes a list of slaves, removes slaves from grid (forgets slaves options)
widget.grid_remove(slaves)  # takes a list of slaves, removes slaves from grid (remembers slaves options)

WINDOWS AND DIALOGS

CREATING TOPLEVEL WINDOW

Python
1
2
3
4
5
tlw = Toplevel(parent)  # parent of root window, no need to grid it

window.destroy()
# can destroy every widget
# destroying parent also destroys it's children

CHANGING BEHAVIOR AND STYLE

Python
# WINDOW TILE
window.title()  # returns title of the window
window.title('new title')  # sets title

# SIZE AND LOCATION
window.geometry(geo_specs)
'''full geometry specification: width * height +- x +- y (actual coordinates of screen)
+x --> x pixels from left edge
-x --> x pixels from right edge
+y --> y pixels from top edge
-y --> y pixels from bottom edge'''

# STACKING ORDER
# current stacking order (list from lowest to highest) --- NOT CLEANLY EXPOSED THROUGH TK API
root.tk.eval('wm stackorder ' + str(window))
# check if window is above or below
if (root.tk.eval('wm stackorder '+str(window)+' isabove '+str(otherwindow))=='1')
if (root.tk.eval('wm stackorder '+str(window)+' isbelow '+str(otherwindow))=='1')
# raise or lower windows
window.lift()  # absolute position
window.lift(otherwin)  # relative to other window
window.lower()  # absolute position
window.lower(otherwin)   # relative to other window

# RESIZE BEHAVIOR
window.resizable(boolean, boolean)  # sets if resizable in width (1st param) and width (2nd param)
window.minsize(num, num)  # sets min width and height
window.maxsize(num, num)  # sets max width and height

# ICONIFYING AND WITHDRAWING
# WINDOW STATE: normal. iconic (iconified window), withdrawn, icon, zoomed
window.state()  # returns current window state
window.state('state')  # sets window state
window.iconify()  # iconifies window
window.deiconify()  # deiconifies window

STANDARD DIALOGS

Python
# SLEETING FILE AND DIRECTORIES
# on Windows and Mac invokes underlying OS dialogs directly
from tkinter import filedialog
filename = filedialog.askopenfilename()
filename = filedialog.asksaveasfilename()
dirname = filedialog.askdirectory()
'''All of these commands produce modal dialogs, which means that the commands (and hence the program) will not continue running until the user submits the dialog.
The commands return the full pathname of the file or directory the user has chosen, or return an empty string if the user cancels out of the dialog.'''

# SELECTING COLORS
from tkinter import colorchooser
 # returns HEX color code, INITIALCOLOR: exiting color, presumably to replace
colorchooser.askcolor(initialcolor=hex_color_code)

# ALERT AND COMFIRMATION DIALOGS
from tkinter import messagebox
messagebox.showinfo(title="title", message='text')  # simple box with message and OK button
messagebox.showerror(title="title", message='text')
messagebox.showwarning(title="title", message='text')
messagebox.askyesno(title="title", message='text', detail='secondary text' icon='icon')
messagebor.askokcancel(message='text', icon='icon', title='title', detail='secondary text', default=button)  # DEFAULT: default button, ok or cancel
messagebox.akdquestion(title="title", message='text', detail='secondary text', icon='icon')
messagebox.askretrycancel(title="title", message='text', detail='secondary text', icon='icon')
messagebox.askyesnocancel(title="title", message='text', detail='secondary text', icon='icon')
# ICON: info (default), error, question, warning

POSSIBLE ALERT/CONFIRMATION RETURN VALUES:

  • ok (default) -- "ok"
  • okcancel -- "ok" or "cancel"
  • yesno -- "yes" or "no"
  • yesnocancel -- "yes", "no" or "cancel"
  • retrycancel -- "retry" or "cancel"

SEPARATOR

Python
# horizontal or vertical line between groups of widgets
separator = ttk.Separator(parent, orient=direction)
# DIRECTION: horizontal, vertical
'''LABEL FRAME'''
# labelled frame, used to group widgets
lf = ttk.LabelFrame(parent, text='label')
'''PANED WINDOWS'''
# stack multimple resizable widgets
# panes ara adjustable (drag sash between panes)
pw = ttk.PanedWindow(parent, orient=direction)
# DIRECTION: horizontal, vertical
lf1 = ttk.LabelFrame(...)
lf2 = ttk.LabelFrame(...)
pw.add(lf1)  # add widget to paned window
pw.add(lf2)
pw.insert(position, subwindow)  # insert widget at given position in list of panes (0, ..., n-1)
pw.forget(subwindow)  # remove widget from pane
pw.forget(position)  # remove widget from pane

NOTEBOOK

Allows switching between multiple pages

Python
nb = ttk.Notebook(parent)
f1 = ttk.Frame(parent, ...)  # child of notebook
f2 = ttk.Frame(parent, ...)
nb.add(subwindow, text='page title', state=flag)
# TEXT: name of page, STATE: normal, dusabled (not selectable), hidden

nb.insert(position, subwindow, option=value)
nb.forget(subwindow)
nb.forget(position)
nb.tabs()  # retrieve all tabs
nb.select()  # return current tab
nb.select(position/subwindow)  # change current tab
nb.tab(tabid, option)  # retrieve tab (TABID: position or subwindow) option
nb.tab(tabid, option=value)   # change tab option

FONTS, COLORS, IMAGES

NAMED FONTS

Creation of personalized fonts

Python
1
2
3
4
from tkinter import font
font_name = font.Font(family='font_family', size=num, weight='bold/normal', slant='roman/italic', underline=boolean, overstrike=boolean)
# FAMILY: Courier, Times, Helvetica (support guaranteed)
font.families()  # all avaiable font families

COLORS

Specified w/ HEX RGB codes.

IMAGES

imgobj = PhotoImage(file='filename') label['image'] = imgobj

IMAGES W/ Pillow

Python
from PIL import ImageTk, Image
myimg = ImageTk.PhotoImage(Image.open('filename'))