Lekce 1 - Úvod do tvorby GUI pomocí knihovny tkinter v Pythonu
Vítejte u prvního tutoriálu kurzu tvorby GUI aplikací v
Pythonu. Naučíme se v něm tvořit uživatelské rozhraní pro
aplikace. Využijeme k tomu knihovnu Pythonu tkinter
.
Požadavky pro úspěšné absolvování kurzu
K úspěšnému zvládnutí tohoto kurzu potřebujeme znalosti v rozsahu kurzů Základní konstrukce jazyka Python a Objektově orientované programování v Pythonu. Na škodu není ani znalost grafického designu, včetně barev, typografie, uspořádání prvků a podobně. To nám umožní vytvářet esteticky působivé a funkční aplikace.
Balíčky pro tvorbu GUI
Naše programy si zatím vystačily s obyčejnými vestavěnými funkcemi
print()
a input()
pro vstup a výstup programu. Je
načase si ukázat také tvorbu grafického rozhraní. Pro Python existují tři
nejznámější balíčky na tvorbu formulářových okenních aplikací -
tkinter
, wxPython
a PyQt
. Poslední dva
jmenované jsou přeportované z C++. Každý z nich má své výhody a
nevýhody. V tomto kurzu budeme používat knihovnu tkinter
. Ze
všech tří jmenovaných je nejjednodušší, ale na druhou stranu také
nejvíce zastaralá. Tato knihovna je většinou instalovaná společně s
Pythonem.
Všechny tři výše zmíněné balíčky jsou multiplatformní, takže si samy zajistí požadovaný vzhled podle operačního systému.
Co znamená zkratka GUI?
GUI (zkratka pro Grafical User Interface) je typ uživatelského rozhraní, které umožňuje interakci s počítačem pomocí grafických prvků.
Uživatelé mohou k ovládání aplikace a provádění funkcí používat myš, klávesnici a dotykové obrazovky. GUI se používá pro většinu moderních aplikací a umožňuje snadnou a intuitivní interakci s počítačem, díky čemuž mohou s programem pracovat i lidé, kteří nerozumí psaní a manipulaci s kódem.
Knihovna tkinter
Hlavní výhodou použití knihovny tkinter
při tvorbě GUI
aplikací v Pythonu je její nenáročnost. Výhod je ale více:
- jednoduchost a snadnost použití: knihovna poskytuje mnoho předdefinovaných widgetů a funkcí, což zjednodušuje proces tvorby aplikací,
- platformní nezávislost: knihovna je součástí standardní distribuce Pythonu a funguje na všech platformách,
- flexibilita: knihovna umožňuje vytvářet aplikace s různým rozložením a funkcionalitou,
- snadná integrace s jinými knihovnami a moduly: knihovnu můžeme snadno integrovat s jinými knihovnami a moduly v jazyce Python, díky čemuž jsme schopni vytvářet komplexní aplikace s různými funkcemi.
Mezi nevýhody knihovny tkinter
pak patří:
- omezené možnosti vzhledu,
- nízká úroveň abstrakce,
- nedostatečná dokumentace,
- omezená podpora pro komplexní aplikace.
Jak jsme si již řekli, tkinter
je součástí standardní
instalace Pythonu. Otevřeme si tedy v našem IDE nový projekt a dostupnost
knihovny si ověříme importem:
import tkinter
Pokud by IDE vypsalo chybu, doinstalujeme tkinter
v něm nebo
pomocí pip v terminálu:
Instalace tkinter:
pip install tkinter
Tvorba okna
Syntaxe pro psaní GUI programů pomocí tkinter
se podobá WPF
v C# nebo Java Swing v Javě a všechen kód budeme psát ručně Tvorba prázdného okna ale i tak
zabere jen pár řádek.
Nejdříve si ukážeme kompletní kód a ten si poté rozebereme:
import tkinter class MainWindow(tkinter.Frame): def __init__(self, parent): super().__init__(parent) self.parent = parent self.parent.title("První GUI aplikace") root = tkinter.Tk() app = MainWindow(root) app.mainloop()
Nejprve tedy importujeme knihovna tkinter
. Na dalších
řádcích si definujeme třídu, která se bude jmenovat
MainWindow
. Tato třída obvykle obsahuje různé formulářové
prvky jako své atributy. Jelikož chceme, aby třída MainWindow
byla okno, musíme ji zdědit ze třídy Frame
(rám). Potom
definujeme konstruktor __init__()
, který se zavolá při
inicializaci okna. V něm musíme zavolat inicializaci rodiče okna, kterého
dostaneme jako parametr při vytváření okna. Navíc si rodiče uložíme,
abychom mohli provádět další akce, jako například nastavení titulku
okna.
Poté vytvoříme kořen aplikace (root
, instance třídy
Tk
), který nám obstarává mj. zobrazení okna, minimalizaci a
ukončení aplikace. Pak vytvoříme instanci aplikace (app
) a
spustíme hlavní cyklus programu, metodu mainloop()
.
GUI programy fungují tak, že se nacházejí v následujícím cyklu:
- zpracuj vstup,
- aktualizuk,
- vykresli.
Díky tomu, že nás root
od tohoto cyklu odstiňuje, nemusíme
ho definovat ručně (na rozdíl např. od her napsaných pomocí modulu
Pygame
).
Náš program nyní vypadá takto:

Nyní do našeho okna přidáme komponentu label
, což je
textový popisek. Vytvoříme další metodu a nazveme ji
create_widgets()
. V této metodě bude probíhat
vytváření komponent. Metodu zavoláme na konci konstruktoru
__init__()
. Náš kód bude vypadat takto:
import tkinter class MainWindow(tkinter.Frame): def __init__(self, parent): super().__init__(parent) self.parent = parent self.parent.title("První GUI aplikace") self.create_widgets() def create_widgets(self): self.label = tkinter.Label(text="Hello world!") root = tkinter.Tk() app = MainWindow(root) app.mainloop()
Všechny komponenty, které vytvoříme, budou atributy třídy, která danou
komponentu obsahuje. V našem případě bude label
atribut třídy
MainWindow
.
Geometrické manažery
Náš label
se zatím nezobrazuje, protože ho napřed musíme
do okna umístit. K dispozici máme tři způsoby.
Metoda pack()
První způsob je za pomoci zabalení metodou pack()
. Komponentu
label
tedy umístíme tak, že na ní zavoláme metodu
pack()
:
def create_widgets(self): self.label = tkinter.Label(text="Hello world!") self.label.pack()
Výsledek vypadá takto:

Metoda pack()
má různé dostupné parametry. Zde jsou hlavní
z nich:
- expand nastaví, zda-li komponenta zabere místo v rodiči,
pokud tam nějaké bude (
True
neboFalse
), - fill nastaví vyplnění rodičovského okna jako:
tkinter.NONE
(nevyplňovat),tkinter.X
(vodorovně),tkinter.Y
(svisle) nebotkinter.BOTH
(oba směry), - side určí, ke které straně bude komponenta ukotvená:
tkinter.TOP
(horní hrana),tkinter.BOTTOM
(spodní hrana),tkinter.LEFT
(levá hrana) nebotkinter.RIGHT
(pravá hrana).
Nyní do okna přidáme další label
, abychom viděli, co
jednotlivé parametry dělají. Navíc přidáme popiskům barvu pozadí, takže
přesně uvidíme, jaké místo zabírají.
Zde je pozměněný kód v metodě create_widgets()
:
def create_widgets(self): self.label_1 = tkinter.Label(text="Hello world!", bg="white") # bílý label self.label_2 = tkinter.Label(text="Hello world!", bg="yellow") # žlutý label # nastavení geometrie self.label_1.pack(side=tkinter.TOP, fill=tkinter.X, expand=True) self.label_2.pack(side=tkinter.BOTTOM, fill=tkinter.Y, expand=True) print(help(self.label_1.pack)) # zde je kód pro nápovědu
Po roztáhnutí bude okno vypadat takto:

Metoda place()
Druhý způsob umístění komponent je za pomoci metody
place()
. Komponenta se do okna umístí pomocí zadání
souřadnic. Tento způsob se hodí maximálně pro dialogy s pevným
umístěním komponent.
Parametry metody jsou:
- souřadnice
x
, - souřadnice
y
, - anchor - neboli místo v komponentě, kde bude bod se souřadnicemi.
Možnosti jsou stejné, jako světové strany:
tkinter.N
(sever),tkinter.S
(jih),tkinter.W
(západ),tkinter.E
(východ),tkinter.NW
(severozápad),tkinter.NE
(severovýchod),tkinter.SW
(jihozápad),tkinter.SE
(jihovýchod) atkinter.CENTER
(střed).
Nyní vytvoříme dva textové popisky, jeden bude mít ukotvení nahoře a
druhý dole. Kód v metodě create_widgets()
bude vypadat
takto:
def create_widgets(self): self.label_1 = tkinter.Label(text="Hello world!", bg="white") self.label_2 = tkinter.Label(text="Hello world!", bg="yellow") self.label_1.place(x=40, y=60, anchor=tkinter.N) self.label_2.place(x=40, y=60, anchor=tkinter.S)
Vidíme, že bílý label je pod žlutým, jelikož bílý má kotevní bod nahoře, zatímco žlutý dole:

Metoda grid()
Třetím a nejlepším způsobem umístění komponent je použití
mřížky/tabulky pomocí metody grid()
. Metoda rozdělí okno
(nebo jakýkoli jiný widget) na mřížku řádků a sloupců. Komponenty pak
umístíme na specifické pozice v této mřížce použitím parametrů
řádků a sloupců (row
a column
). Jedna komponenta
může zabírat i více buněk a každý řádek nebo sloupec může mít jinou
váhu při přidělování místa.
Váhu řádků a sloupců nastavíme při inicializaci okna v konstruktoru
__init__()
. Váha určuje, jak se přidělí dodatečné místo v
okně nebo rámu mezi jednotlivé řádky nebo sloupce, když uživatel
zvětší velikost okna. V naší aplikaci budeme chtít mít dvakrát
label
pod sebou, takže použijeme tabulku 2x1 (dva řádky a jeden
sloupec):
def __init__(self, parent): super().__init__(parent) self.parent = parent self.parent.title("První GUI aplikace") self.parent.rowconfigure(0, weight=500) self.parent.rowconfigure(1, weight=500) self.parent.columnconfigure(0, weight=1000) self.create_widgets()
Váhy řádků a sloupců se nastavují přes metody
rowconfigure()
a columnconfigure()
. Jako první
poziční parametr je číslo řádku/sloupce a poté jako klíčový parametr
je jeho váha (weight
). Tu jsme pro řádky rozdělili rovnoměrně
na polovinu a sloupci jsme dali celou hodnotu.
Metody pack()
a grid()
nelze
použít dohromady!
Metoda grid()
má tyto parametry:
row
: číslo sloupce,column
: číslo řádky,rowspan
: zabrání více řádků (jejich počet),columnspan
: zabrání více sloupců (jejich počet),sticky
: zarovnání v buňce;tkinter.N
(sever),tkinter.S
(jih),tkinter.W
(západ),tkinter.E
(východ),tkinter.NW
(severozápad),tkinter.NE
(severovýchod),tkinter.SW
(jihozápad),tkinter.SE
(jihovýchod) atkinter.NSEW
(zabere celou buňku)- odsazení:
padx
,pady
(vnější odsazení) aipadx
,ipady
(vnitřní odsazení).
Nyní si ukážeme kompletní kód pro grid:
import tkinter class MainWindow(tkinter.Frame): def __init__(self, parent): super().__init__(parent) self.parent = parent self.parent.title("První GUI aplikace") self.parent.rowconfigure(0, weight=500) self.parent.rowconfigure(1, weight=500) self.parent.columnconfigure(0, weight=1000) self.create_widgets() def create_widgets(self): self.label_1 = tkinter.Label(text="Hello world!", bg="white") self.label_2 = tkinter.Label(text="Hello world!", bg="yellow") self.label_1.grid(row = 0, column = 0, sticky=tkinter.NSEW) self.label_2.grid(row = 1, column = 0, sticky=tkinter.NSEW) root = tkinter.Tk() app = MainWindow(root) app.mainloop()
Výsledek vypadá takto:

Další možnosti okna
Oknu je také vhodné nastavit minimální, případně maximální velikost. Stejně tak můžeme nastavit i zda půjde okno roztahovat:
self.parent.minsize(500, 200) # minimální velisost self.parent.maxsize(1000, 600) # maximální velikost self.parent.resizable(True, True) # je okno měnitelné
Pokud chceme, aby se nám při spuštění skriptu nezobrazovala
konzole, musíme změnit příponu souboru z .py
na
.pyw
.
V další lekci, Aplikace Kalkulačka v tkinter - MVC model,si rozplánujeme kalkulačku na základě knihovny
tkinter
pomocí MVC a sestavíme si třídy pro jednotlivé
komponenty.