1. díl - Úvod do tkinteru v Pythonu

Python Tkinter Ú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:

Jednoduché okno v tkinteru

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:

tkinter – použití pack

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:

tkinter v Pythonu – Pack a další metody

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.

tkinter v Pythonu – Ukázka place

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:

tkinter v Pythonu – Ukázka grid

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ě se podíváme podrobněji na labely a tlačítka a zkusíme si napsat GUI kalkulačku.


 

Stáhnout

Staženo 79x (914 B)
Aplikace je včetně zdrojových kódů v jazyce Python

 

  Aktivity (1)

Článek pro vás napsal gcx11
Avatar
(^_^)

Jak se ti líbí článek?
Celkem (9 hlasů) :
4.888894.888894.888894.888894.88889


 


Miniatura
Všechny články v sekci
Okenní aplikace v Pythonu pomocí tkinter

 

 

Komentáře

Avatar
hanpari
Redaktor
Avatar
hanpari:

Výborný díl, opravdu se ti povedl.

 
Odpovědět  +2 6.1.2015 18:31
Avatar
qwertyW
Redaktor
Avatar
qwertyW:

gcx11 V první ukázce kodu mas misto MainWindow HlavniOkno

Odpovědět 11.2.2015 18:41
Programuji, tedy jsem.
Avatar
Jiří Nekolný:

Musím se připojit k hanparimu. Fakt dobrý díl.

 
Odpovědět 13. dubna 22:38
Avatar
Ocepox
Člen
Avatar
Ocepox:

Velmi by mě potěšilo pokračování.

 
Odpovědět 20. června 13:38
Avatar
gcx11
Redaktor
Avatar
Odpovídá na Ocepox
gcx11:

Pokud budu mít čas, tak bych mohl něco sepsat, ale nic neslibuji. Ale delší dobu jsem v tom tkinteru nedělal, takže si nejsem jistý, jestli se mi povede udělat stejně dobrý díl.

 
Odpovědět 22. června 11:50
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 5 zpráv z 5.