Hlavní navigace

Grafické uživatelské rozhraní v Pythonu: knihovna Tkinter (2.část)

1. 8. 2017
Doba čtení: 21 minut

Sdílet

Ve třetí části seriálu o knihovnách pro tvorbu GUI v Pythonu si popíšeme další koncepty, na nichž je postavena knihovna Tkinter. Budeme se zabývat nastavováním stylů, změnou témat a použitím proměnných, které přímo „sledují“ stav zvoleného widgetu.

Obsah

1. Styly ovládacích prvků u původních widgetů knihovny Tk

2. Nastavování stylů u widgetů z knihovny Ttk

3. Předpřipravená témata nabízená knihovnou Ttk

4. Výběr tématu za běhu programu

5. Nastavení stylů pro jednotlivá témata

6. Vizuální podoba okrajů tlačítek

7. Změna konfigurace mřížky – padding

8. Změna šířky okrajů tlačítek

9. Použití manažeru geometrie „pack“

10. Widget checkbutton

11. Proměnná, která bude automaticky sledovat stav checkbuttonu

12. Explicitní nastavení hodnot sledovací proměnné

13. Widget entry

14. Proměnná s obsahem vstupního textového pole

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

16. Odkazy na Internetu

1. Styly ovládacích prvků u původních widgetů knihovny Tk

Dnes si nejprve ukážeme, jakým způsobem je možné nastavit styly ovládacích prvků. V případě použití původní knihovny Tk je to snadné. Příkladem může být nastavení pozadí tlačítka:

button1 = tkinter.Button(root, background='yellow', text="1st btn",
                         command=lambda: sys.exit(0))

Možné je použít i barvu specifikovanou způsobem, který pravděpodobně znáte z HTML stránek (takzvaný hex triplet):

button2 = tkinter.Button(root, background='#ff8080', text="Second button",
                         command=lambda: sys.exit(0))

Barvu (či jakoukoli jinou vlastnost) můžeme nastavit později, a to přes metodu configure:

button3.configure(background='#8080ff')

Alternativní způsob zápisu bez použití metody configure, je nejkratší a používá přetížení []:

button4['background'] = '#80ff80'

Všechny tři možnosti jsou použity v dnešním prvním demonstračním příkladu:

#!/usr/bin/env python
 
import tkinter
 
import sys
 
root = tkinter.Tk()
 
button1 = tkinter.Button(root, background='yellow', text="1st btn",
                         command=lambda: sys.exit(0))
button2 = tkinter.Button(root, background='#ff8080', text="Second button",
                         command=lambda: sys.exit(0))
button3 = tkinter.Button(root, text="Third button",
                         command=lambda: sys.exit(0))
button4 = tkinter.Button(root, text="This is fourth button, the last one",
                         command=lambda: sys.exit(0))
 
button3.configure(background='#8080ff')
button4['background'] = '#80ff80'
 
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 1: Čtyři tlačítka, každé s odlišným pozadím.

2. Nastavování stylů u widgetů z knihovny Ttk

U widgetů nabízených nadstavbovou knihovnou Ttk (neboli „themed Tk“) se jejich vizuální styly nastavují odlišně a výše uvedený příklad by při náhradě konstruktoru tkinter.Button za konstruktor ttk.Button nepracoval korektně). Nejprve je totiž nutné explicitně vytvořit nový styl, pojmenovat ho, nastavit jeho vlastnosti (například barvu pozadí) a teprve poté tento styl přiřadit ke zvolenému ovládacímu prvku. Toto řešení sice může vypadat komplikovaně (a nepochybně je delší), ovšem oddělení stylů od konkrétních komponent je vhodnější ve chvíli, kdy má mít celá aplikace konzistentní vzhled, který je současně nutné jednoduchými zásahy modifikovat. Ostatně prakticky stejný problém je řešen u statických webových stránek i u webových aplikací použitím kaskádních stylů (CSS). Podívejme se nyní na to, jak je možné změnit pozadí čtyř tlačítek z knihovny Ttk. Nejdříve si vytvoříme objekt reprezentující pojmenované styly (můžeme jim říkat třídy) a přiřadíme mu vizuální vlastnosti:

style = ttk.Style()
style.configure('Yellow.TButton', background='yellow')
style.configure('Red.TButton', background='#ff8080')
style.configure('Blue.TButton', background='#8080ff')
style.configure('Green.TButton', background='#80ff80')

Pojmenované třídy stylu potom přiřadíme jednotlivým ovládacím prvkům:

button1 = ttk.Button(root, text="1st btn", style='Yellow.TButton',
                     command=exit)
button2 = ttk.Button(root, text="Second button", style='Red.TButton',
                     command=exit)

Přiřazení lze ovšem v případě potřeby provést až po konstrukci příslušného ovládacího prvku. Existují dvě varianty zápisu, přičemž varianta druhá je sice kratší, ovšem bez přímé kontroly, jaký atribut se vlastně nastavuje:

button3.configure(style='Green.TButton')
 
button4["style"] = 'Blue.TButton'

Předchozí příklad je tedy možné relativně snadno upravit takovým způsobem, aby se namísto tlačítek tkinter.Button používala tlačítka tkinter.ttk.Button:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
style.configure('Yellow.TButton', background='yellow')
style.configure('Red.TButton', background='#ff8080')
style.configure('Blue.TButton', background='#8080ff')
style.configure('Green.TButton', background='#80ff80')
 
button1 = ttk.Button(root, text="1st btn", style='Yellow.TButton',
                     command=exit)
button2 = ttk.Button(root, text="Second button", style='Red.TButton',
                     command=exit)
button3 = ttk.Button(root, text="Third button",
                     command=exit)
button4 = ttk.Button(root, text="This is fourth button, the last one",
                     command=exit)
 
button3.configure(style='Green.TButton')
 
button4["style"] = 'Blue.TButton'
 
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 2: Tlačítka z knihovny Ttk s nastaveným stylem pozadí.

3. Předpřipravená témata nabízená knihovnou Ttk

V předchozí kapitole jsme viděli, že v nadstavbové knihovně Ttk je možné v případě potřeby měnit styly jednotlivých komponent. Ovšem co přesně znamená slovo „themed“ v plném názvu této knihovny? Kromě stylů totiž tato knihovna obsahuje předpřipravená témata (themes), v nichž je poměrně přesně definován vzhled i chování komponent. Některá témata jsou navržena takovým způsobem, aby se výsledná aplikace podobala nativním aplikacím (i když označení „nativní“ má zejména na Linuxu poměrně vágní význam), další témata emulují původní vzhled komponent knihovny Tk (s Motifem) atd. Seznam existujících témat je dostupný na adrese https://wiki.tcl.tk/48689, ovšem v této tabulce si všímejte především těch témat, která jsou označena built-in (tedy jsou dostupná ve standardní instalaci knihovny Ttk) a současně u nich není v poznámce napsáno „systém_xyz only“. Další témata je samozřejmě možné v případě potřeby doinstalovat a pokud to licence umožňuje, distribuovat je společně s aplikací.

Seznam aktuálně nainstalovaných a dostupných témat se získá velmi jednoduše, a to přímo za běhu aplikace:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
style = ttk.Style()
 
print(style.theme_names())

Na Linuxu by se měla vypsat následující témata:

  1. clam
  2. alt
  3. default
  4. classic

4. Výběr tématu za běhu programu

Téma je možné vybrat i změnit prakticky kdykoli za běhu programu, což skutečně funguje (například ve Swingu je to problematičtější). Podívejme se však na to, co se stane, když si pomocí čtyř tlačítek necháme přepínat čtyři základní témata „clam“, „alt“, „default“ a „classic“ a současně bude nastaven styl Red.TButton. Téma přepneme jednoduše zavoláním:

style.theme_use("jméno_tématu"))

kde style je objekt získaný konstruktorem:

style = ttk.Style()

Příklad změny tématu po stisku tlačítka:

button1 = ttk.Button(root, text="clam",
                     command=lambda: style.theme_use("clam"))

Úplný demonstrační příklad se změnou témat za běhu vypadá následovně:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
 
style.configure('Red.TButton', background='#ff8080')
 
button1 = ttk.Button(root, text="clam",
                     command=lambda: style.theme_use("clam"))
button2 = ttk.Button(root, text="alt",
                     command=lambda: style.theme_use("alt"))
button3 = ttk.Button(root, text="default",
                     command=lambda: style.theme_use("default"))
button4 = ttk.Button(root, text="classic",
                     command=lambda: style.theme_use("classic"))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
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")
 
quitButton.grid(column=2, row=5, sticky="we")
 
label = tkinter.Label(root, text='Hello world')
entry = tkinter.Entry(root)
checkbutton = tkinter.Checkbutton(text='Do you like Tkinter?')
 
checkbutton.grid(column=1, row=3, columnspan=2, sticky="w")
label.grid(column=1, row=4)
entry.grid(column=2, row=4)
 
root.mainloop()

Obrázek 3: Demonstrační příklad po výběru tématu „default“.

Program sice skutečně bude plně funkční, ovšem tlačítko [Quit] bude červené pouze při zvolení jednoho tématu, zatímco u ostatních témat bude zachována původní barva. Toto chování je korektní (můžeme si to představit tak, že téma je slovník obsahující styly), ovšem je nutné na něj myslet ve chvíli, kdy uživatelům současně umožňujeme změnu tématu a nastavujeme vlastní styly. Způsob řešení tohoto problému si ukážeme v navazující kapitole.

Obrázek 4: Demonstrační příklad po výběru tématu „classic“.

5. Nastavení stylů pro jednotlivá témata

Pokud si skutečně budete přát nastavit nějaký styl, například barvu pozadí vybraných tlačítek, pro všechna témata (což ovšem nemusí být vždy to nejlepší řešení) či pro vybraná témata, lze na začátku aplikace (tedy ještě než se zobrazí hlavní okno) spustit tuto programovou smyčku, která vždy téma nastaví jako výchozí a ihned poté se změní příslušný styl:

for style_name in ('clam', 'alt', 'default', 'classic'):
    style.theme_use(style_name)
    style.configure('Red.TButton', background='#ff8080')

Úplný demonstrační příklad se změnou témat za běhu i s nastavením stylů pro jednotlivá témata vypadá následovně:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
 
for style_name in ('clam', 'alt', 'default', 'classic'):
    style.theme_use(style_name)
    style.configure('Red.TButton', background='#ff8080')
 
button1 = ttk.Button(root, text="clam",
                     command=lambda: style.theme_use("clam"))
button2 = ttk.Button(root, text="alt",
                     command=lambda: style.theme_use("alt"))
button3 = ttk.Button(root, text="default",
                     command=lambda: style.theme_use("default"))
button4 = ttk.Button(root, text="classic",
                     command=lambda: style.theme_use("classic"))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
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")
 
quitButton.grid(column=2, row=5, sticky="we")
 
label = tkinter.Label(root, text='Hello world')
entry = tkinter.Entry(root)
checkbutton = tkinter.Checkbutton(text='Do you like Tkinter?')
 
checkbutton.grid(column=1, row=3, columnspan=2, sticky="w")
label.grid(column=1, row=4)
entry.grid(column=2, row=4)
 
root.mainloop()

Obrázek 5: Výběr tématu „clam“.

Obrázek 6: Výběr tématu „default“.

Obrázek 7: Výběr tématu „alt“.

Obrázek 8: Výběr tématu „classic“.

6. Vizuální podoba okrajů tlačítek

U tlačítka lze, podobně jako u mnoha dalších ovládacích prvků, přesně specifikovat, jak má v okně vypadat. Kromě zadání jména fontu a barvy popředí i pozadí je možné zadat tvar okraje tlačítka. Vyzkoušejte si následující příklad, který ukazuje všechny možnosti tvarů okraje tlačítek:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
style.configure('Red.TButton', background='#ff8080')
 
button1 = tkinter.Button(root, text="sunken", relief="sunken")
button2 = tkinter.Button(root, text="solid", relief="solid")
button3 = tkinter.Button(root, text="flat", relief="flat")
button4 = tkinter.Button(root, text="groove", relief="groove")
button5 = tkinter.Button(root, text="raised", relief="raised")
button6 = tkinter.Button(root, text="ridge", relief="ridge")
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
button1.grid(column=1, row=1, sticky="we")
button2.grid(column=1, row=2, sticky="we")
button3.grid(column=1, row=3, sticky="we")
button4.grid(column=1, row=4, sticky="we")
button5.grid(column=1, row=5, sticky="we")
button6.grid(column=1, row=6, sticky="we")
 
quitButton.grid(column=2, row=6, sticky="we")
 
root.mainloop()

Obrázek 9: Šest typů okrajů tlačítek.

Zdrojový kód příkladu lze i zkrátit, přičemž využijeme toho, že tvary okrajů tlačítek jsou reprezentovány řetězci, takže tlačítka i jejich vlastnosti lze vytvořit v jediné smyčce (generátorová notace seznamu) a přidat je do okna ve smyčce další:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
style.configure('Red.TButton', background='#ff8080')
 
buttonStyles = ("sunken", "solid", "flat", "groove", "raised", "ridge")
 
buttons = (tkinter.Button(root, text=buttonStyle, relief=buttonStyle)
           for buttonStyle in buttonStyles)
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
for i, button in enumerate(buttons):
    button.grid(column=1, row=i, sticky="we")
 
quitButton.grid(column=2, row=6, sticky="we")
 
root.mainloop()

Obrázek 10: Šest typů okrajů tlačítek.

7. Změna konfigurace mřížky – padding

Pokud se vám zdá, že jsou ovládací prvky v mřížce příliš nalepeny na sebe, je možné mezi jednotlivé buňky mřížky vložit výplň. Ta se specifikuje u funkce grid pojmenovaným parametrem padx pro horizontální výplň a parametrem pady pro výplň vertikální:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
style.configure('Red.TButton', background='#ff8080')
 
buttonStyles = ("sunken", "solid", "flat", "groove", "raised", "ridge")
 
buttons = (tkinter.Button(root, text=buttonStyle, relief=buttonStyle)
           for buttonStyle in buttonStyles)
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
for i, button in enumerate(buttons):
    button.grid(column=1, row=i, sticky="we", padx=6, pady=6)
 
quitButton.grid(column=2, row=6, sticky="we", padx=6, pady=6)
 
root.mainloop()

Obrázek 11: Nastavení hodnot padx a pady na hodnotu 6.

8. Změna šířky okrajů tlačítek

Okraje tlačítek mají většinou šířku pouhého jednoho pixelu, což mimochodem ovlivňuje vzhled okrajů typu „groove“, „ridge“ a „raised“. Ovšem díky flexibilitě knihovny Tk je samozřejmě možné i tuto vlastnost změnit, a to konkrétně pojmenovaným parametrem borderwidth:

buttons = (Button(root, text=buttonStyle, relief=buttonStyle, borderwidth=2)
           for buttonStyle in buttonStyles)

Podívejme se na úplný zdrojový kód tohoto příkladu:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
style.configure('Red.TButton', background='#ff8080')
 
buttonStyles = ("sunken", "solid", "flat", "groove", "raised", "ridge")
 
buttons = (Button(root, text=buttonStyle, relief=buttonStyle, borderwidth=2)
           for buttonStyle in buttonStyles)
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
for i, button in enumerate(buttons):
    button.grid(column=1, row=i, sticky="we", padx=6, pady=6)
 
quitButton.grid(column=2, row=6, sticky="we", padx=6, pady=6)
 
root.mainloop()

Obrázek 12: Šířka okrajů tlačítek je nastavena na dva pixely.

9. Použití manažeru geometrie „pack“

Jen ve stručnosti si ukažme, jakým způsobem je možné použít manažer geometrie nazvaný „pack“. S tímto správcem jsme se vlastně již setkali v předchozím článku, takže si připomeňme, že tento manažer umožňuje vkládat komponenty do kontejneru (typicky do okna) tak, že se zadává jejich relativní umístění (horizontální či vertikální zarovnání):

button1.pack()
button2.pack()
button3.pack()
button4.pack()

Pro jednodušší dialogy může být tento správce použitelnější jednodušeji, než správce „grid“ (není nutné počítat řádky a sloupce), což je možná patrné z dalšího demonstračního příkladu:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
style.configure('Red.TButton', background='#ff8080')
 
button1 = ttk.Button(root, text="1s button", command=exit)
button2 = ttk.Button(root, text="2nd button with long text", command=exit)
button3 = ttk.Button(root, text="3rd button", command=exit)
button4 = ttk.Button(root, text="4th button", command=exit)
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
button1.pack()
button2.pack()
button3.pack()
button4.pack()
 
label = tkinter.Label(root, text='Hello world')
entry = tkinter.Entry(root)
checkbutton = tkinter.Checkbutton(text='Do you like Tkinter?')
 
checkbutton.pack()
label.pack()
entry.pack()
 
quitButton.pack()
 
root.mainloop()

Obrázek 13: Widgety jsou umístěny pod sebou, což je implicitní chování manažeru geometrie „pack“.

10. Widget checkbutton

Dalším typem grafického ovládacího prvku (widgetu) je takzvaný checkbutton, dnes poněkud nepřesně nazývaný checkbox. Od obyčejného tlačítka se tento widget liší především tím, že je vizuálně patrný jeho stav – nastaveno/nenastaveno. Tento typ tlačítek je zobrazován různým způsobem, typicky se však jedná o čtvereček, který je buď zatržený (znak ✓ či ×) nebo prázdný; v některých GUI prostředích se však stav tlačítka reprezentuje pouze jeho barvou. V nejjednodušším případě se přepínací tlačítko vytvoří následovně:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
root = tkinter.Tk()
 
style = ttk.Style()
style.configure('Red.TButton', background='#ff8080')
 
checkbutton = ttk.Checkbutton(root, text="Delete Internet?",
                              command=lambda: print("changed"))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
checkbutton.grid(column=1, row=1, sticky="we", padx=6, pady=6)
quitButton.grid(column=1, row=2, sticky="we", padx=6, pady=6)
 
root.mainloop()

Obrázek 14: Checkbutton nastavený do polohy „off“, použito je téma „default“.

Obrázek 15: Checkbutton nastavený do polohy „off“, použito je téma „default“.

Jak je patrné z předešlých dvou screenshotů, není checkbutton ve výchozím stylu vykreslen nijak vábně. Lepší je – alespoň podle mého názoru – použít styl „alt“, v němž je checkbutton vykreslen přece jen civilizovanějším způsobem. Příklad stačí nepatrně upravit:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
root = tkinter.Tk()
 
style = ttk.Style()
style.theme_use("alt")
style.configure('Red.TButton', background='#ff8080')
 
checkbutton = ttk.Checkbutton(root, text="Delete Internet?",
                              command=lambda: print("changed"))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
checkbutton.grid(column=1, row=1, sticky="we", padx=6, pady=6)
quitButton.grid(column=1, row=2, sticky="we", padx=6, pady=6)
 
root.mainloop()

Obrázek 16: Checkbutton nastavený do polohy „off“, použito je téma „alt“.

Obrázek 17: Checkbutton nastavený do polohy „off“, použito je téma „alt“.

11. Proměnná, která bude automaticky sledovat stav checkbuttonu

Velmi praktická je další vlastnost widgetu checkbutton. Stav přepínacího tlačítka je totiž možné navázat na vybranou proměnnou, která tak bude automaticky sledovat jeho stav. Pokud je tlačítko nastaveno (je v něm znak × nebo ✓), bude do proměnné implicitně vložena hodnota 1, pokud je naopak nenastaveno, nastaví se nulová hodnota. Sledující proměnnou je nutné vytvořit konstruktorem tkinter.IntVar() a specifikovat ji pojmenovaným parametrem variable:

delete_internet = tkinter.IntVar()
 
checkbutton = ttk.Checkbutton(root, text="Delete Internet?",
                              variable=delete_internet)

K hodnotě sledující proměnné se můžeme dostat s využitím getteru, tedy metody get():

checkbutton = ttk.Checkbutton(root, text="Delete Internet?",
                              variable=delete_internet,
                              command=lambda: print(delete_internet.get()))

Vše je patrné z následujícího demonstračního příkladu:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
root = tkinter.Tk()
 
style = ttk.Style()
style.theme_use("alt")
style.configure('Red.TButton', background='#ff8080')
 
delete_internet = tkinter.IntVar()
 
checkbutton = ttk.Checkbutton(root, text="Delete Internet?",
                              variable=delete_internet,
                              command=lambda: print(delete_internet.get()))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
checkbutton.grid(column=1, row=1, sticky="we", padx=6, pady=6)
quitButton.grid(column=1, row=2, sticky="we", padx=6, pady=6)
 
root.mainloop()

12. Explicitní nastavení hodnot sledovací proměnné

Kromě dalších možností je možné pomocí voleb onvalue a offvalue zvolit, jakých hodnot bude daná „sledovací“ proměnná nabývat v případě, že je tlačítko nastaveno i nenastaveno. Nastavme nejdříve sledovací proměnnou na typ řetězec:

delete_internet = tkinter.StringVar()

Potom můžeme specifikovat, že pro zatržený checkbox bude sledovací proměnná obsahovat řetězec „yes“ a pro checkbox nezatržený pak hodnotu „no“. Tím lze ušetřit další zbytečnou explicitně zapsanou logiku v programu:

checkbutton = ttk.Checkbutton(root, text="Delete Internet?",
                              variable=delete_internet,
                              onvalue="yes",
                              offvalue="no",)

Opět si ukažme celý příklad:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
root = tkinter.Tk()
 
style = ttk.Style()
style.theme_use("alt")
style.configure('Red.TButton', background='#ff8080')
 
delete_internet = tkinter.StringVar()
 
checkbutton = ttk.Checkbutton(root, text="Delete Internet?",
                              variable=delete_internet,
                              onvalue="yes",
                              offvalue="no",
                              command=lambda: print(delete_internet.get()))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
checkbutton.grid(column=1, row=1, sticky="we", padx=6, pady=6)
quitButton.grid(column=1, row=2, sticky="we", padx=6, pady=6)
 
root.mainloop()

13. Widget entry

S využitím widgetu typu entry je možné v okně či dialogu zobrazit jeden řádek textu. Od minule popsaného widgetu label se tento widget liší především v tom, že zobrazený řádek textu je možné editovat. Při editaci jsou k dispozici základní klávesy pro pohyb kurzoru (šipka doleva, šipka doprava, klávesa [Home] a klávesa [End]) a mimo jiné také další klávesové zkratky, které jsou známé například z shellu či editoru Emacs, Joe a Pico: [Ctrl+A] (posun na začátek textu), [Ctrl+E] (posun na konec textu). K tomu připočítejme dnes již standardní klávesy pro práci se schránkou: [Ctrl+C], [Ctrl+V] a [Ctrl+X] a na některých systémech i kombinace kláves [Ctrl+Insert], [Shift+Insert] a [Shift+Delete]. Bude ovšem fungovat i použití výběru, tedy stisk prostředního tlačítka myši vloží obsah výběru do widgetu entry. Text se do widgetu přiřazuje metodou insert:

entry = ttk.Entry(root)
entry.insert(0, "xyzzy")

Použití tohoto widgetu si ukážeme na příkladu, ve kterém zobrazíme dialog s textovým políčkem a tlačítkem Quit. První verze dialogu může vypadat například následovně:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
root = tkinter.Tk()
 
style = ttk.Style()
style.theme_use("alt")
style.configure('Red.TButton', background='#ff8080')
 
entry = ttk.Entry(root)
entry.insert(0, "xyzzy")
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
entry.grid(column=1, row=1, sticky="we", padx=6, pady=6)
quitButton.grid(column=1, row=2, sticky="we", padx=6, pady=6)
 
root.mainloop()

Obrázek 18: Dialog s widgetem „entry“.

14. Proměnná s obsahem vstupního textového pole

I k widgetu entry je možné zaregistrovat „sledovací proměnnou“, jejíž hodnota bude reflektovat stav textu v tomto prvku. Sledovací proměnná bude mít typ StringVar:

value = tkinter.StringVar()

Nastavení sledování:

entry = ttk.Entry(root, textvariable=value)

V dnešním posledním příkladu se po stisku tlačítka „Show var“ na standardní výstup vypíše aktuální text ve widgetu:

ict ve školství 24

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
root = tkinter.Tk()
 
style = ttk.Style()
style.theme_use("alt")
style.configure('Red.TButton', background='#ff8080')
 
value = tkinter.StringVar()
 
entry = ttk.Entry(root, textvariable=value)
entry.insert(0, "xyzzy")
 
showButton = ttk.Button(root, text="Show var",
                        command=lambda: print(value.get()))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
entry.grid(column=1, row=1, sticky="we", padx=6, pady=6)
showButton.grid(column=1, row=2, sticky="we", padx=6, pady=6)
quitButton.grid(column=1, row=3, sticky="we", padx=6, pady=6)
 
root.mainloop()

Obrázek 19: Po stisku tlačítka „Show var“ se na standardní výstup vypíše hodnota proměnné, která sleduje obsah widgetu „entry“.

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
15_button_styles.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/15_button_sty­les.py
16_ttk_styles.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/16_ttk_sty­les.py
17_themes.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/17_themes­.py
18_theme_selection.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/18_theme_se­lection.py
19_theme_settings_and_selection.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/19_theme_set­tings_and_selection.py
20_button_styles.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/20_button_sty­les.py
21_button_styles2.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/21_button_sty­les2.py
22_grid_padding.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/22_grid_pad­ding.py
23_border_width.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/23_border_wid­th.py
24_pack_manager.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/24_pack_ma­nager.py
25_checkbutton.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/25_checkbut­ton.py
26_checkbutton_alt_theme.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/26_checkbut­ton_alt_theme.py
27_checkbox_variable.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/27_checkbox_va­riable.py
28_checkbox_specific_values.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/28_checkbox_spe­cific_values.py
29_entry.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/29_entry.py
30_entry_variable.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/Tkinter/30_entry_va­riable.py

16. Odkazy na Internetu

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

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.