Lekce 11 - Úvod do tkinteru v Pythonu
Python Okenní aplikace Úvod do tkinteru v Pythonu


Vítejte u pokračování seriálu o Pythonu. Nyní budeme pokračovat tvorbou uživatelského rozhraní. V dnešním díle si vytvoříme jednoduchou okenní aplikaci s uživatelským rozhraním (GUI - Graphic User Interface). Až do teď jsme používali pro naše programy CLI (Command Line Interface). Pro tvorbu GUI aplikací byste měli znát alespoň základy OOP v Pythonu.
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. Pro Python existují asi tři nejznámější multiplatformní balíčky na tvorbu formulářových okenních aplikací - tkinter (postavený na Tcl/Tk), wxPython (wxWidgets pro Python) a PyQt (Qt pro Python). Poslední dva jmenované jsou přeportované z C++. Každý z nich má své výhody a nevýhody. V této sekci budeme používat tkinter. Z těchto tří jmenovaných je nejjednodušší, ale na druhou stranu asi nejvíce zastaralý. Tkinter je většinou instalovaný společně s Pythonem. Ovládací prvky v tkinteru nevypadají příliš hezky, ale můžeme si pomoci použitím rozšíření tkinteru - ttk a tix. Na konci dílu použijeme ttk.
Tři hlavní výše zmíněné balíčky (tkinter, wxPython a PyQt) jsou multiplatformní, takže si samy zajistí požadovaný vzhled podle operačního systému.
Tvorba okna
Otevřeme si nový soubor. Syntaxe pro psaní GUI programů v tkinteru se
podobá WF v C# nebo Java Swing v Javě a všechen kód budeme psát ručně.
Ale nebojte, tvorba
prázdného okna zabere jen pár řádek.
Nejdříve si ukážeme kompletní kód a ten si poté rozebereme.
#!/usr/bin/env python3 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()
Rozbor
První dva řádky jsou celkem jasné. První je shell bang a na druhém se importuje knihovna tkinter.
#!/usr/bin/env python3 import 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, tak ji musíme zdědit ze třídy Frame (rám). Potom definujeme metodu __init__(), která se zavolá při inicializaci okna. V ní 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.
class MainWindow(tkinter.Frame): def __init__(self, parent): super().__init__(parent) self.parent = parent self.parent.title("První GUI aplikace")
Na konci souboru vytvoříme kořen aplikace (root), který nám obstarává např. zobrazení okna, minimalizaci, ukončení aplikace... Poté vytvoříme objekt aplikace (app) a spustíme hlavní cyklus programu, metodu mainloop().
root = tkinter.Tk() app = MainWindow(root) app.mainloop()
GUI programy fungují tak, že se nacházejí v následujícím cyklu: zpracuj vstup, aktualizuj a vykresli. Díky tomu, že nás root od tohoto cyklu odstiňuje, tak si ho nemusíme definovat ručně, na rozdíl např. od her napsaných pomocí modulu Pygame.
Náš program nyní vypadá zhruba takto:

Nyní zkusíme do našeho okna přidat jednu komponentu. Tou komponentou bude label, což je textový popisek. Vytvoříme další metodu a to create_widgets(). V této metodě bude probíhat vytváření komponent. Tuto metodu zavoláme na konci speciální metody __init__(). Takže 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 tomto případě bude label atribut třídy MainWindow.
Geometrické manažery
Label se nám zatím nezobrazuje, protože ho napřed musíme do okna umístit. Můžeme použít tři způsoby:
Pack
První způsob je za pomoci použití zabalení (pack). Hodí se pro vyplnění nějaké jiné komponenty (např. Frame) nebo na skládání komponent vertikálně (svisle) nebo horizontálně (vodorovně).
Label umístíme tak, že na komponentě zavoláme metodu pack.
def create_widgets(self): self.label = tkinter.Label(text="Hello world!") self.label.pack()
Výsledek:

Dále můžeme nastavit různé parametry pro metodu pack. Zde jsou některé z nich:
- expand: Nastaví, zda-li komponenta zabere místo v rodiči, pokud tam nějaké bude (True nebo False)
- fill: Nastaví vyplnění rodičovského okna. Možnosti jsou: tkinter.NONE (nevyplňovat), tkinter.X (vodorovně), tkinter.Y (svisle) nebo tkinter.BOTH (oba směry)
- side: Určí, ke které straně bude komponenta ukotvená. Možnosti jsou: tkinter.TOP (horní hrana), tkinter.BOTTOM (spodní hrana), tkinter.LEFT (levá hrana) nebo tkinter.RIGHT (pravá hrana).
Pokud chcete prozkoumat další, stačí použít funkci help().
Nyní do okna přidáme další label, abychom viděli, co jednotlivé parametry dělají. Navíc přidáme labelům barvu pozadí, tak 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 nějak takto:

Place
Druhý způsob je za pomoci umístění (place). Komponenta se do okna umístí pomocí zadání souřadnic. Pro umístění komponenty se používá metoda place(). Tento způsob se hodí maximálně pro dialogy s pevným umístěním komponent.
Její parametry jsou:
- x: Souřadnice x
- y: Souřadnice y
- anchor: 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) a tkinter.CENTER (střed).
Nyní vytvoříme 2 textové popisky, jeden bude mít ukotvení nahoře a druhý dole. Kód v metodě 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.place(x=40, y=60, anchor=tkinter.N) self.label_2.place(x=40, y=60, anchor=tkinter.S)
Vidíte, že bílý label je pod žlutým, jelikož bílý má ten bod nahoře, zatímco žlutý dole.

Grid
Třetí a nejlepší způsob je použití mřížky/tabulky (grid). Určíme její velikost a do buněk tabulky poté vkládáme jednotlivé komponenty. 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.
Ale aby nám to fungovalo, musíme napřed rodiči nastavit váhu řádků a sloupců. Tu nastavíme při inicializaci okna v metodě __init__(). V naší aplikaci budeme chtít mít dva labely dané pod sebe, takže použijeme tabulku 2x1 (2 řádky a 1 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() (pro řádek) a columnconfigure() (pro sloupec). 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.
V metodě create_widgets() poté použijeme metodu grid(). Nikdy nepoužívejte metody pack() a grid() 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) a tkinter.NSEW (zabere celou buňku)
- dále jsou možné parametry: padx, pady (vnější odsazení) a ipadx, ipady (vnitřní odsazení)
Nyní si ukážeme kompletní kód pro grid:
#!/usr/bin/env python3 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 vhodné nastavit minimální velikost. Stejně tak můžeme nastavit i maximální velikost a 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 chcete, aby se vám nezobrazovala konzole, musíte změnit příponu souboru z .py na .pyw
Příště, v lekci Tvorba kalkučky v tkinteru, se podíváme podrobněji na labely a tlačítka a zkusíme si napsat GUI kalkulačku.
Stáhnout
Staženo 141x (914 B)
Aplikace je včetně zdrojových kódů v jazyce Python
Komentáře
Zobrazeno 6 zpráv z 6.