Hlavní navigace

Grafické uživatelské rozhraní v Pythonu: knihovna Tkinter

Pavel Tišnovský

Prvním systémem pro tvorbu grafického uživatelského rozhraní Pythonu, který si popíšeme, je Tkinter. Jedná se o standardní knihovnu pro GUI pro Python, ovšem její největší předností je velmi snadné použití a možnost rozšiřování sady widgetů o další ovládací prvky.

Obsah

1. Grafické uživatelské rozhraní v Pythonu: knihovna Tkinter

2. Widgety

3. Kontejnery

4. Základní typy widgetů v knihovně Tk/Tkinter

5. Vlastnosti widgetů

6. První příklad: zobrazení okna s textem „Hello world!“

7. Události a reakce na ně

8. Druhý příklad: tlačítko reagující na stisk

9. Třetí příklad: použití anonymní funkce pro reakci na stlačení tlačítka

10. Správci umístění (geometrie) widgetů

11. Čtvrtý, pátý a šestý příklad: umístění čtyř tlačítek do mřížky a do jediného sloupce

12. Sedmý, osmý a devátý příklad: prázdná místa v mřížce, spojení buněk mřížky

13. „Přilepení“ widgetů k okrajům buněk mřížky

14. Příklady 11 až 14 – různé varianty „přilepení“ tlačítek k mřížce

15. Repositář s demonstračními příklady

16. Odkazy na Internetu

1. Grafické uživatelské rozhraní v Pythonu: knihovna Tkinter

Standardní knihovnou pro tvorbu grafického uživatelského rozhraní v Pythonu je stále Tkinter. Ostatně i jedno ze základních IDE pro Python – IDLE – tuto knihovnu používá (viz dva přiložené screenshoty). Interně se v knihovně Tkinter inicializuje interpret jazyka Tcl sloužící pro ovládání knihovny Tk, ovšem s tímto interním mechanismem se prakticky nemusíme setkat (snad jen v chybových hlášeních, které mohou být z tohoto důvodu někdy dosti kryptické). Největší předností Tkinteru je skutečně snadná a přímočará tvorba grafického uživatelského rozhraní, která je navíc podpořena přímočaře použitelnými správci rozmístění ovládacích prvků (taktéž se setkáme s pojmenováním správci geometrie), což znamená, že se při použití Tkinteru mnohdy obejdeme bez nutnosti používat GUI editory.

Obrázek 1: Jednoduché integrované vývojové prostředí IDLE používá Tkinter.

Důležitá poznámka: na tomto místě je vhodné upozornit na to, že ovládací prvky (widgety) nabízené Tkinterem (a interně tudíž knihovnou Tk), mohou působit poněkud zastarale. Částečné řešení spočívá v náhradě původních widgetů za Ttk (Themed Tk), což také budeme v demonstračních příkladech dodržovat. Widgety nabízené Ttk se od původních widgetů odlišují zejména v tom, že se snaží dodržet zvyklosti panující na konkrétním operačním systému a desktopovém prostředí, kde je aplikace spuštěna. To například znamená, že na Mac OS X se budou widgety chovat odlišně, než na Microsoft Windows či na Linuxu s GNOME. Navíc se u Ttk změnil způsob nastavování vlastností widgetů, který je více konzistentní a do určité míry se podobá kaskádním stylům (CSS) známým z webového světa; naproti tomu původní sada widgetů spíše připomíná explicitní nastavování stylů značek přímo v HTML.

Obrázek 2: Další screenshot integrovaného vývojového prostředí IDLE.

2. Widgety

Základem prakticky všech v současnosti používaných grafických uživatelských rozhraní jsou takzvané widgety, které jsou někdy poněkud nepřesně označovány také jako komponenty. Z pohledu uživatele aplikací s grafickým uživatelským rozhraním se jedná o grafické prvky zobrazené na obrazovce, které mají předem známé chování a předvídatelnou funkci. V mnoha případech je chování widgetů standardizováno či alespoň doporučováno – viz například doporučení pro (dnes již notně zastaralý) Motif, Microsoft Windows, Mac OS a v neposlední řadě také doporučení pro GNOME a KDE. Velká část widgetů se snaží svým vzhledem do jisté míry reflektovat objekty z reálného světa (tlačítka, „teploměry“, přepínače programů, objekty známé z papírových formulářů apod.). Z pohledu programátora je naproti tomu widget objektem, kterému lze nastavit určitý stav a který reaguje na události, které při své práci generuje uživatel (přesouvání objektů na obrazovce, stlačování obrazů tlačítek pomocí myši či stylusu, psaní textu, gesta na dotykové obrazovce atd.).

3. Kontejnery

Samotné widgety nejsou na obrazovce prakticky nikdy zcela osamocené, ostatně většina knihoven pro GUI by samostatný widget nedokázala zobrazit. Ve skutečnosti se téměř vždy nachází v nějakém okně, dialogu či dalším nadřazeném widgetu. Programátoři grafických uživatelských rozhraní se často setkají s pojmem kontejner. Jedná se o komponentu, na kterou lze vkládat různé widgety a mnohdy i další kontejnery. Obecně tak interně vzniká stromová datová struktura jejíž kořen je představován plochou na obrazovce, na které jsou umístěna okna aplikací (dnes je ovšem i samotná plocha obrazovky součástí větší virtuální plochy zobrazované obecně na více monitorech). V těchto oknech se dále nachází kontejnery a widgety. V mnoha grafických uživatelských rozhraních přitom mohou být vybrané widgety (zdaleka ne však všechny) současně i kontejnery. Kontejnery kromě jiného řeší i rozmístění widgetů na své ploše.

Způsobů pro rozmisťování widgetů do kontejnerů existuje více. Základní dělení je na kontejnery, kde jsou widgety umisťovány absolutně (do této kategorie patří WinAPI, MFC, OWL a VCL) a naopak kontejnery, které widgety většinou umisťují podle své velikosti a vzájemných vztahů (zde se nachází javovské AWT, Swing, GTK, Qt, Tk/Tkinter a mnoho dalších). V toolkitu Tk a tím pádem i v Tkinteru se mohou widgety umisťovat několika různými způsoby (pack, place a grid).

4. Základní typy widgetů v knihovně Tk/Tkinter

V průběhu mnoha let se množina widgetů používaných v různých grafických uživatelských rozhraních postupně rozšiřovala, ostatně postačí se podívat na obrázky z prvních grafických rozhraní navržených ve společnosti Xerox a porovnat je s moderním desktopem. Současně však také docházelo ke sjednocování vzhledu jednotlivých widgetů i jejich chování na různých platformách. Vzhled samozřejmě není na všech platformách přesně stejný, to však pro uživatele většinou nemusí představovat významnější praktický problém, na rozdíl od odlišného chování celého prostředí i jednotlivých widgetů.

V toolkitu Tk je k dispozici poměrně velké množství widgetů, podobně jako v dalších moderních toolkitech. Navíc dnes widgety existují ve dvou podobách – starší (původní) a novější (Ttk neboli „themed Tk“), které lépe odpovídají požadavkům uživatelů současných desktopových prostředí a jejichž vzhled a chování se může od původních widgetů odlišovat. V následující tabulce je uveden seznam základních typů widgetů. Pro mnoho aplikací je níže uvedená skupina widgetů dostačující, avšak v případě, že aplikace potřebuje vytvořit nový widget, je to samozřejmě možné, protože knihovna Tk je navržena tak, že ji lze poměrně jednoduchým způsobem rozšiřovat. V následující tabulce si také můžete všimnout toho, že některé widgety jsou pojmenovány odlišným způsobem od dnes používané terminologie. Vychází to z faktu, že Tcl/Tk je mnohem starší než většina dnešních toolkitů.

Jméno widgetu Význam a funkce
label widget, který zobrazuje v okně či dialogu měnitelný text
button graficky zobrazené tlačítko, které implicitně reaguje na levé tlačítko myši
checkbutton dvoustavový přepínač, který implicitně reaguje na levé tlačítko myši
radiobutton widget, jichž může být sdruženo větší množství, vždy pouze jeden je vybraný
scale dnes nazýván pojmem slider atd., jedná se o widget s posuvnou částí a přidruženým textem, kde se zobrazuje hodnota v závislosti na poloze posuvné části
entry widget, do kterého je možné zapisovat text, k tomu má přidruženo mnoho klávesových zkratek (jde o kombinaci staršího a novějšího standardu)
spinbox widget určený pro zadávání číselných hodnot kombinací klávesnice a myši (i s kontrolou mezí)
menu vertikální menu, které se skládá z více položek
menubutton používá se spolu s menu pro vytváření jednotlivých položek
listbox widget, jež nabízí na výběr libovolné množství řádků s textem
scrollbar podobné widgetu scale s tím rozdílem, že zobrazuje posuvné šipky a naopak nezobrazuje přidruženou číselnou hodnotu
frame jeden z několika nabízených kontejnerů; tento má tvar obdélníka (může být také neviditelný nebo může mít 3D rámeček)
toplevel další z kontejnerů, tento se chová jako samostatné okno či dialog
bitmap bitmapa, tj. rastrový obrázek
photo/photoimage rastrový obrázek, jež může být načten z externího souboru v mnoha různých formátech
canvas widget, na který lze programově vkládat další grafické komponenty (úsečky, oblouky, kružnice, polyčáry, text atd.)

Výše zmíněné widgety budou podrobněji popsány v navazujícíh částech tohoto seriálu. Zde se pouze chci zmínit o pěkně pojatých menu. Jednotlivá vertikální menu se totiž mohou od mateřského okna „odpoutat“ a chovat se jako samostatné okno či dialog. Díky tomu lze celou aplikaci zachovat po grafické stránce velmi kompaktní a nechat na uživateli, zda a kdy si jednotlivá menu zobrazí v samostatných oknech. Aplikace přitom může používat jak hlavní menu, tak i libovolné množství menu příručních (kontextových, pop-up). Podobný způsob práce s menu je k vidění například u textového editoru Vim (ovšem pouze v některých prostředích) nebo v grafickém editoru MtPaint.

5. Vlastnosti widgetů

Ke každému widgetu je možné nastavit mnoho různých vlastností, které mění buď jeho vizuální vzhled na obrazovce počítače nebo jeho chování, tj. způsob reakce widgetu na akce uživatele. Mezi tyto akce počítáme například kliknutí tlačítkem myši, použití klávesových zkratek (hot keys), přesunutí widgetu atd. Některé vlastnosti jsou všem widgetům společné, další vlastnosti jsou však jedinečné pro jeden či pouze několik typů widgetů. Je to ostatně logické, některé widgety mají speciální chování. Vlastnosti lze nastavovat již při vytváření widgetů, na druhou stranu je také možné vlastnosti měnit až při běhu aplikace. Způsob nastavení vlastností si ukážeme na demonstračních příkladech. V následující tabulce jsou uvedeny vlastnosti, které jsou společné prakticky všem widgetům (kromě speciálních widgetů typu „položka menu“, které mají vlastnosti omezeny, stejně tak jako jejich reakce na uživatelovu činnost). Pozor! – při použití Ttk se nastavování vizuálních vlastností musí provádět přes styly, což si samozřejmě taktéž ukážeme:

Jméno vlastnosti Popis vlastnosti
background barva pozadí widgetu v případě, že widget není aktivní (vybraný)
foreground barva popředí widgetu (například zobrazeného textu) v případě, že widget není aktivní (vybraný)
borderwidth šířka okraje widgetu, která je zadaná v pixelech
activebackground barva pozadí widgetu v případě, že je widget vybrán (typicky kurzorem myši)
activeforeground barva popředí widgetu v případě, že je widget vybrán
disabledforeground barva popředí widgetu v případě, že je ovládání widgetu zakázáno
relief způsob prostorového zobrazení widgetu
compound způsob umístění bitmapy či obrázku na widgetu
bitmap bitmapa, která má být ve widgetu zobrazena
image obrázek, který má být ve widgetu zobrazen (více o bitmapách a obrázcích bude uvedeno v dalších dílech)
font jméno fontu, který je použit pro text uvnitř widgetu (font lze specifikovat platformově nezávislým způsobem)
text text, který má být ve widgetu (tlačítko, položka menu atd.) zobrazen
cursor jméno kurzoru myši, který bude použit v případě, že se kurzor nachází nad widgetem
textvariable jméno proměnné, která je nastavována podle uživatelových manipulací s widgetem (StringVar v Tkinteru)
justify zarovnání textu ve widgetu v případě, že se zobrazuje více řádků
anchor způsob umístění textu či obrázku ve widgetu

Vlastnosti se nastavují dvěma způsoby – u původních widgetů přímo nastavením vlastnosti (například background=„red“) u „themed Tk“ pak změnou takzvaných stylů, což je sice nepatrně složitější, ovšem mnohem flexibilnější způsob.

6. První příklad: zobrazení okna s textem „Hello world!“

Prakticky nejjednodušším příkladem je zobrazení okna s×textovou informací neboli návěštím (label). Tuto úlohu, kterou jsme si ostatně již ukazovali v úvodním článku pro mnoho různých toolkitů, je možné řešit tak, že se nejprve vytvoří okno (toplevel widget) a do něho se vloží widget typu label, který požadovanou textovou informaci zobrazuje. K dispozici přitom máme dva typy tohoto widgetu – jak původní z knihovny Tk, tak i návěští z Ttk:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
root = Tk()
 
label = ttk.Label(root, text="Hello world!")
 
label.pack()
 
root.mainloop()

Na řádku:

root = Tk()

je vytvořeno okno a současně je mu interně přiřazen interpret jazyka Tcl, přes který se všechny GUI operace provádí (se samotným Tcl však do styku nemusíme přijít).

Na následujícím řádku:

label = ttk.Label(root, text="Hello world!")

je vytvořeno textové návěští a je přiřazeno k vytvořenému oknu.

Další řádek je velmi důležitý, protože se zde používá takzvaný správce geometrie pack. Správci geometrie jsou používáni pro umisťování widgetů do okna. Konkrétně správce pack dokáže widgety umisťovat horizontálně či vertikálně, takže je jeho použití velmi jednoduché (a současně má tento správce hodně omezení).

Poslední řádek spustí interní smyčku, v níž se postupně získávají a zpracovávají události z fronty událostí. Taková smyčka se většinou nazývá event loop:

root.mainloop()

Obrázek 3: Spuštění příkladu v Linuxu (Fluxbox).

Příklad ve skutečnosti není úplný, protože není naprogramováno uzavření okna. Tento problém vyřešíme tak, že do okna vložíme další widget, tentokrát typu button. Po stlačení tohoto tlačítka se okno korektně uzavře. Nejprve si však musíme vysvětlit koncept událostí (events)

Obrázek 4: Díky tomu, že je toolkit Tk použitelný i v dnes již zastaralých systémech, lze stejný příklad spustit například i na obstarožních Windows XP.

7. Události a reakce na ně

Při programování grafických uživatelských rozhraní je často používán pojem události (event(s)). Událostmi řízené programování je ostatně s programováním GUI prakticky neoddělitelně spojeno. Každý widget může v průběhu svého života generovat nějaké události. Naprostá většina událostí vzniká tak, že uživatel s widgetem interaktivně pracuje (například stlačí tlačítko zobrazené na obrazovce). Ke každému widgetu je příslušná jedna „implicitní“ událost, na kterou reaguje. Tato událost se nastavuje pomocí změny vlastnosti widgetu, což bude ukázáno v demonstračních příkladech v následujících kapitolách. Kromě implicitní události lze na widgety navázat i další události, například tlačítko (button) může reagovat i na stlačení klávesy na klávesnici, na pravé tlačítko myši či na rolování kolečkem myši. Toto navázání se provádí pomocí příkazu bind, který obsahuje množství voleb. Musíme si však uvědomit, že některé události se na různých operačních systémech a desktopových prostředích mohou generovat různým způsobem – typicky se jedná o přesun fokusu.

8. Druhý příklad: tlačítko reagující na stisk

V dnešním druhém demonstračním příkladu přidáme do okna další ovládací prvek (widget). Bude se jednat o tlačítko, které bude reagovat na svůj stisk, což je jedna ze základních uživatelem vyvolaných událostí, které mohou v GUI vzniknout. Při vytváření tlačítka můžeme přes nepovinný pojmenovaný parametr command určit, která funkce se při stisku tlačítka zavolá (jedná se tedy o takzvanou callback funkci):

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = Tk()
 
label = ttk.Label(root, text="Hello world!")
button = ttk.Button(root, text="Close window", command=exit)
 
label.pack()
button.pack()
 
root.mainloop()

Obrázek 5: Spuštění druhého příkladu ve Fluxboxu (vzhled ovládacích prvků Tkinteru je poměrně strohý, bez grafických efektů).

Obrázek 6: Běh na Windows.

9. Třetí příklad: použití anonymní funkce pro reakci na stlačení tlačítka

Pozor si musíte dát na to, že se předává skutečně jen jméno funkce (zde exit) a nikoli její parametry. Pokud byste za jméno zapsali kulaté závorky s parametry, funkce by se již při konstrukci tlačítka zavolala a použila by se její návratová hodnota, což většinou není takové chování, jaké požadujeme.

Vzhledem k tomu, že mnoho reakcí na události je velmi jednoduchých, vedlo by vytváření zvláštních funkcí pro každou událost ke zbytečně rozsáhlému kódu. V Pythonu však můžeme použít i jednodušší formu anonymních funkcí (oproti plnohodnotným anonymním funkcím mohou obsahovat výraz, nikoli však řídicí bloky), takže předchozí příklad lze přepsat následovně:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
label = ttk.Label(root, text="Hello world!")
button = ttk.Button(root, text="Close window", command=lambda: sys.exit(0))
 
label.pack()
button.pack()
 
root.mainloop()

Obrázek 7: Spuštění třetího příkladu ve Fluxboxu (screenshot by měl být totožný s obrázkem číslo 3).

10. Správci umístění (geometrie) widgetů

Existují dva základní způsoby, jakými lze vkládat widgety do okna či dialogu. První možností, která byla použita zejména v aplikacích tvořených pomocí WinAPI (Windows API) a MFC (Microsoft Foundation Classes), je absolutní umisťování, například specifikací souřadnic levého horního rohu widgetu a jeho šířky a výšky. Tato možnost je dobře použitelná pouze pro ty aplikace, které mají běžet na jedné platformě s jedním správcem oken. Pro multiplatformní aplikace, u nichž není dopředu známá přesná velikost oken ani rozlišení obrazovky, se často používá druhá možnost, při které jsou widgety umisťováni buď relativně vůči sobě nebo do flexibilních mřížek či dalších tvarů – tento způsob využívají prakticky všechny modernější knihovny widgetů, jakými jsou Qt, GTKSwing.

Oba dva výše zmíněné způsoby jsou v knihovně Tkinter podporovány, používat by se však měl především způsob druhý, tj. relativní umisťování widgetů. Pro umisťování jednotlivých widgetů do okna jsou v Tkinter používáni takzvaní správci (manažeři) geometrie. K dispozici je několik typů těchto správců. V předchozích příkladech jsme používali správce pack, ovšem velmi užitečný je i správce grid.

Poznámka: jméno manažeru grid sice může připomínat například GridLayout z Javy, ovšem Tkinterovská varianta je mnohem jednodušeji použitelná a současně i více flexibilní.

11. Čtvrtý, pátý a šestý příklad: umístění čtyř tlačítek do mřížky a do jediného sloupce

S použitím manažeru grid se widgety umisťují do neviditelné mřížky. Velikost mřížky je automaticky měněna tak, aby se do ní všechny vkládané widgety umístily v „rozumné“ velikosti. Programově je však možné měnit vzdálenost mezi jednotlivými widgety a tím také měnit velikost mřížky. V dalším demonstračním příkladu jsou do okna umístěny čtyři tlačítka (widgety typu button) do jedné mřížky 2×2 buňky:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="First button")
button2 = ttk.Button(root, text="Second button")
button3 = ttk.Button(root, text="Third button")
button4 = ttk.Button(root, text="Fourth button")
 
button1.grid(column=1, row=1)
button2.grid(column=2, row=1)
button3.grid(column=1, row=2)
button4.grid(column=2, row=2)
 
root.mainloop()

Obrázek 8: Čtvrtý demonstrační příklad.

Umístění tlačítek je patrné z dalšího screenshotu. Všimněte si, že bez dalšího explicitního nastavení je každé tlačítko pouze tak velké, aby se do něj vešel zadaný text.

K tlačítkům samozřejmě můžeme přiřadit nějakou akci vyvolanou jejich stlačením:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="First button", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="Fourth button", command=lambda: sys.exit(0))
 
button1.grid(column=1, row=1)
button2.grid(column=2, row=1)
button3.grid(column=1, row=2)
button4.grid(column=2, row=2)
 
root.mainloop()

Obrázek 9: Čtvrtý demonstrační příklad.

Pokud bychom tlačítka umístili do okna manažerem pack, vypadal by výsledek odlišně, i když by se aplikace chovala stejně:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="First button")
button2 = ttk.Button(root, text="Second button with long text")
button3 = ttk.Button(root, text="Third button")
button4 = ttk.Button(root, text="Fourth button")
 
button1.pack()
button2.pack()
button3.pack()
button4.pack()
 
root.mainloop()

Obrázek 10: Použití správce geometrie pack.

12. Sedmý, osmý a devátý příklad: prázdná místa v mřížce, spojení buněk mřížky

Můžeme si také vyzkoušet změnit umístění jednotlivých tlačítek v mřížce. Pokud není do nějaké buňky mřížky vložen widget, je tato plocha prázdná:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="First button")
button2 = ttk.Button(root, text="Second button")
button3 = ttk.Button(root, text="Third button")
button4 = ttk.Button(root, text="Fourth button")
 
button1.grid(column=2, row=4)
button2.grid(column=3, row=1)
button3.grid(column=1, row=3)
button4.grid(column=4, row=2)
 
root.mainloop()

Obrázek 11: Čtyři tlačítka v pomyslné mřížce 4×4 buňky.

Opět můžeme k tlačítkům přiřadit nějakou akci vyvolanou jejich stlačením:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="First button", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="Fourth button", command=lambda: sys.exit(0))
 
button1.grid(column=2, row=4)
button2.grid(column=3, row=1)
button3.grid(column=1, row=3)
button4.grid(column=4, row=2)
 
root.mainloop()

Obrázek 12: Čtyři tlačítka v pomyslné mřížce 4×4 buňky.

Navíc lze widgety pomocí parametrů columnspan a rowspan nastavit tak, aby obsadily více sousedních buněk (pokud se ovšem widgety nezvětší na celou plochu buňky, nebude toto nastavení vždy viditelné):

from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="First button", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="Fourth button", command=lambda: sys.exit(0))
 
button1.grid(column=1, row=1)
button2.grid(column=2, row=2)
button3.grid(column=1, row=3, columnspan=2)
button4.grid(column=4, row=1, rowspan=3)
 
root.mainloop()

Obrázek 13: Tlačítka přesahující přes několik buněk.

13. „Přilepení“ widgetů k okrajům buněk mřížky

Widget je možné „přilepit“ k vybraným okrajům buňky (či buněk), a to konkrétně pomocí vlastnosti nazvané sticky. V nejjednodušším případě se této vlastnosti přiřazuje řetězec, který může obsahovat libovolnou kombinaci písmen n (north), s (south), e (east) nebo w (west). Widget je po zadání této vlastnosti přilepen ke specifikovaným okrajům buňky, což mj. může znamenat, že dojde k jeho zvětšení.

14. Příklady 11 až 14 – různé varianty „přilepení“ tlačítek k mřížce

V této kapitole si ukážeme, jak lze modifikovat následující příklad, v němž je zobrazena čtveřice tlačítek v mřížce 2×2 buňky:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="1st btn", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="This is fourth button, the last one",
                     command=lambda: sys.exit(0))
 
button1.grid(column=1, row=1)
button2.grid(column=2, row=1)
button3.grid(column=1, row=2)
button4.grid(column=2, row=2)
 
root.mainloop()

Obrázek 14: Implicitně jsou tlačítka v buňkách pouze vycentrována.

Všechna tlačítka jsou „přilepena“ k západnímu (tedy levému) okraji svých buněk:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="1st btn", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="This is fourth button, the last one",
                     command=lambda: sys.exit(0))
 
button1.grid(column=1, row=1, sticky="w")
button2.grid(column=2, row=1, sticky="w")
button3.grid(column=1, row=2, sticky="w")
button4.grid(column=2, row=2, sticky="w")
 
root.mainloop()

Obrázek 15: Přilepení tlačítek k západnímu (levému) okraji buněk.

Všechna tlačítka jsou „přilepena“ k východnímu (tedy pravému) okraji svých buněk:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="1st btn", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="This is fourth button, the last one",
                     command=lambda: sys.exit(0))
 
button1.grid(column=1, row=1, sticky="e")
button2.grid(column=2, row=1, sticky="e")
button3.grid(column=1, row=2, sticky="e")
button4.grid(column=2, row=2, sticky="e")
 
root.mainloop()

Obrázek 16: Přilepení tlačítek k východnímu (pravému) okraji buněk.

Všechna tlačítka jsou „přilepena“ jak k západnímu, tak i k východnímu okraji, což mj. znamená, že pod sebou ležící tlačítka mají shodnou šířku:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="1st btn", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="This is fourth button, the last one",
                     command=lambda: sys.exit(0))
 
button1.grid(column=1, row=1, sticky="we")
button2.grid(column=2, row=1, sticky="we")
button3.grid(column=1, row=2, sticky="we")
button4.grid(column=2, row=2, sticky="we")
 
root.mainloop()

Obrázek 17: Výplň celé buňky tlačítky, které jsou přilepené k západní i východní straně.

Poslední tlačítko obsazuje celý třetí sloupec mřížky a je navíc přilepeno k severnímu (hornímu) i jižnímu (spodnímu) okraji:

#!/usr/bin/env python
 
from tkinter import *
from tkinter import ttk
 
import sys
 
root = Tk()
 
button1 = ttk.Button(root, text="1st btn", command=lambda: sys.exit(0))
button2 = ttk.Button(root, text="Second button", command=lambda: sys.exit(0))
button3 = ttk.Button(root, text="Third button", command=lambda: sys.exit(0))
button4 = ttk.Button(root, text="This is fourth button, the last one",
                     command=lambda: sys.exit(0))
 
button1.grid(column=1, row=1, sticky="we")
button2.grid(column=2, row=2, sticky="we")
button3.grid(column=1, row=3, sticky="we")
button4.grid(column=3, row=1, rowspan=4, sticky="nswe")
 
root.mainloop()

Obrázek 18: Čtvrté tlačítko používá „přilepení“ ke všem stranám spojené buňky.

15. Repositář s demonstračními příklady

Zdrojové kódy všech dnešních demonstračních příkladů naleznete pod následujícími odkazy:

Příklad Odkaz
01_label.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/01_label.py
02_button.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/02_button­.py
03_button_and_lambda.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/03_button_an­d_lambda.py
04_buttons_in_regular_grid.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/04_button­s_in_regular_grid.py
05_buttons_in_regular_grid_cmd.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/05_button­s_in_regular_grid_cmd.py
06_buttons_and_pack_manager.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/06_button­s_and_pack_manager.py
07_buttons_in_grid.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/07_button­s_in_grid.py
08_buttons_in_grid_cmd.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/08_button­s_in_grid_cmd.py
09_columnspan.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/09_columns­pan.py
10_no_sticky_buttons.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/10_no_stic­ky_buttons.py
11_sticky_buttons_west.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/11_sticky_but­tons_west.py
12_sticky_buttons_east.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/12_sticky_but­tons_east.py
13_sticky_buttons_west_east.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/13_sticky_but­tons_west_east.py
14_sticky_buttons_north_south.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/14_sticky_but­tons_north_south.py

Obrázek 19: Způsob změny stylu ovládacích prvků jak přímo, tak i s využitím stylů si popíšeme příště.

Obrázek 20: Ukázka dalších základních widgetů.

16. Odkazy na Internetu

  1. TkDocs: Styles and Themes
    http://www.tkdocs.com/tuto­rial/styles.html
  2. Drawing in Tkinter
    http://zetcode.com/gui/tkin­ter/drawing/
  3. Changing ttk widget text color (StackOverflow)
    https://stackoverflow.com/qu­estions/16240477/changing-ttk-widget-text-color
  4. Hra Breakout napísaná v Tkinteri
    https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/
  5. The Hitchhiker's Guide to Pyhton: GUI Applications
    http://docs.python-guide.org/en/latest/scenarios/gui/
  6. 7 Top Python GUI Frameworks for 2017
    http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/
  7. GUI Programming in Python
    https://wiki.python.org/mo­in/GuiProgramming
  8. Cameron Laird's personal notes on Python GUIs
    http://phaseit.net/claird/com­p.lang.python/python_GUI.html
  9. Python GUI development
    http://pythoncentral.io/introduction-python-gui-development/
  10. Graphic User Interface FAQ
    https://docs.python.org/2/faq/gu­i.html#graphic-user-interface-faq
  11. TkInter
    https://wiki.python.org/moin/TkInter
  12. Tkinter 8.5 reference: a GUI for Python
    http://infohost.nmt.edu/tcc/hel­p/pubs/tkinter/web/index.html
  13. TkInter (Wikipedia)
    https://en.wikipedia.org/wiki/Tkinter
  14. appJar
    http://appjar.info/
  15. appJar (Wikipedia)
    https://en.wikipedia.org/wiki/AppJar
  16. appJar na Pythonhosted
    http://pythonhosted.org/appJar/
  17. Stránky projektu PyGTK
    http://www.pygtk.org/
  18. PyGTK (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  19. Stránky projektu PyGObject
    https://wiki.gnome.org/Pro­jects/PyGObject
  20. Stránky projektu Kivy
    https://kivy.org/#home
  21. Stránky projektu PyQt
    https://riverbankcomputin­g.com/software/pyqt/intro
  22. PyQt (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  23. Stránky projektu PySide
    https://wiki.qt.io/PySide
  24. PySide (Wikipedia)
    https://en.wikipedia.org/wiki/PySide
  25. Stránky projektu Kivy
    https://kivy.org/#home
  26. Kivy (framework, Wikipedia)
    https://en.wikipedia.org/wi­ki/Kivy_(framework)
  27. QML Applications
    http://doc.qt.io/qt-5/qmlapplications.html
  28. KDE
    https://www.kde.org/
  29. Qt
    https://www.qt.io/
  30. GNOME
    https://en.wikipedia.org/wiki/GNOME
  31. Category:Software that uses PyGTK
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGTK
  32. Category:Software that uses PyGObject
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGObject
  33. Category:Software that uses wxWidgets
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_wxWidgets
  34. GIO
    https://developer.gnome.or­g/gio/stable/
  35. GStreamer
    https://gstreamer.freedesktop.org/
  36. GStreamer (Wikipedia)
    https://en.wikipedia.org/wi­ki/GStreamer
  37. Wax Gui Toolkit
    https://wiki.python.org/moin/Wax
  38. Python Imaging Library (PIL)
    http://infohost.nmt.edu/tcc/hel­p/pubs/pil/
Našli jste v článku chybu?