Hlavní navigace

Tvorba grafického uživatelského rozhraní v Pythonu: widgety v knihovně appJar

Pavel Tišnovský

Ve druhém článku o knihovně appJar určené pro snadnou tvorbu aplikací s grafickým uživatelským rozhraním se seznámíme se všemi základními ovládacími prvky (widgety), které tato knihovna nabízí. Výklad bude doplněn dvanácti příklady.

Obsah

1. Tvorba grafického uživatelského rozhraní v Pythonu: widgety v knihovně appJar

2. Nastavení volného místa mezi widgety (padding)

3. Ukázka konfigurace mezer mezi widgety v oknu

4. Volné místo a umístění widgetů do mřížky

5. Zaškrtávací pole (check box)

6. Konfigurace zaškrtávacích polí

7. Přepínače (radio buttons)

8. Změna způsobu zobrazení přepínačů

9. Implicitně vybraný přepínač

10. Seznam (listbox)

11. Seznam s možností výběru více prvků

12. Rozbalovací seznam

13. Widgety, které pracují se slovníkem stavů

14. Rozbalovací seznam s výběrem většího množství prvků

15. Ukázka použití rozbalovacího seznamu s možností výběru více prvků

16. Widget se skupinou zaškrtávacích prvků

17. Ukázka použití skupiny zaškrtávacích prvků

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

19. Odkazy na Internetu

1. Tvorba grafického uživatelského rozhraní v Pythonu: widgety v knihovně appJar

Nejdříve se podívejme na způsob implicitního vkládání widgetů do oken či dialogů. Jednoduchý projekt, který je zobrazen pod tímto odstavcem (a o kterém jsme se již bavili minule), po svém spuštění zobrazí okno s textovým návěštím, pod nímž je umístěna dvojice tlačítek. Všechny tři zmíněné widgety jsou přitom „namačkány“ na sobě; mezera mezi nimi je jen minimální:

#!/usr/bin/env python
 
from appJar import gui
 
app = gui()
 
app.setSticky("we")
 
app.addLabel("title", "Hello world!")
 
app.addButton("Ok", None)
app.addButton("Quit", None)
 
app.go()

Obrázek 1: Screenshot předchozího příkladu.

Totéž platí i ve chvíli, kdy budeme widgety umisťovat vedle sebe do pomyslné mřížky – widgety stále budou implicitně „namačkány“ vedle sebe:

#!/usr/bin/env python
 
from appJar import gui
 
app = gui()
 
app.setSticky("we")
 
app.addLabel("title", "Hello world!", colspan=2)
 
app.addButton("Ok", None, 1, 0)
app.addButton("Quit", None, 1, 1)
 
app.go()

Obrázek 2: Screenshot předchozího demonstračního příkladu.

2. Nastavení volného místa mezi widgety (padding)

Pro nastavení horizontálních a vertikálních mezer mezi jednotlivými widgety se používají metody setPadX(), setPadY() a setPadding(). Kromě toho je možné nastavit i interní horizontální a vertikální mezery. Ty se umisťují mezi okraj widgetu (ten je většinou viditelný, například u tlačítka) a vlastním textem a/nebo ovládací částí widgetu. Většinou se velikost interních mezer ponechává na výchozí hodnotě, ale samozřejmě vám nic nebrání laborovat i s těmito parametry:

Metoda Význam
setPadX() mezery mezi buňkami umístěnými vedle sebe
setPadY() mezery mezi buňkami umístěnými nad sebou
setPadding() kombinace předchozích dvou metod
   
setIPadX() interní horizontální mezera mezi okrajem widgetu a jeho textem/ovládací částí
setIPadY() interní vertikální mezera mezi okrajem widgetu a jeho textem/ovládací částí
setIPadding() kombinace předchozích dvou metody
   
setInPadX() totožné se setIPadX()
setInPadY() totožné se setIPadY()
setInPadding() totožné se setIPadding()

Obrázek 3: Změna interní vertikální mezery mezi okrajem widgetu a jeho textem.

Poznámka: ve skutečnosti je možné volat metodu setPadding() dvěma způsoby – předáním dvojice hodnot představujících mezery či předání pole či n-tice s dvojicí prvků, které taktéž představují mezery mezi widg poety.

První způsob:

app.setPadding(x_padding, y_padding)

Alernativní způsob:

app.setPadding([x_padding, y_padding])
app.setPadding((x_padding, y_padding))

3. Ukázka konfigurace mezer mezi widgety v oknu

Podívejme se nyní na použití metody setPadding() v praxi. Mezi widgety budeme vkládat mezeru o šířce/výšce deseti pixelů:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        app.infoBox("Ok, Ok", "Ok button pressed")
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 10)
 
app.addLabel("title", "Hello world!")
 
app.addButton("Ok", onButtonPress)
app.addButton("Quit", onButtonPress)
 
app.go()

Obrázek 4: Screenshot dnešního prvního demonstračního příkladu.

4. Volné místo a umístění widgetů do mřížky

Widgety jsou vždy umisťované do pomyslné mřížky, takže i při explicitním nastavení buňky (buněk), do nichž se widgety mají vložit, se bude velikost těchto buněk zvětšovat o nastavené mezery. Můžeme se o tom snadno přesvědčit po spuštění následujícího příkladu:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        app.infoBox("Ok, Ok", "Ok button pressed")
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 10)
 
app.addLabel("title", "Hello world!")
 
app.addButton("Ok", onButtonPress, 1, 1)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

Poznámka: v současné verzi knihovny appJar není možné specifikovat různé velikosti mezer v různých směrech (na rozdíl od CCS, kde to možné je).

Obrázek 5: Screenshot dnešního druhého demonstračního příkladu.

5. Zaškrtávací pole (check box)

Dalším typem grafického ovládacího prvku (widgetu) je takzvaný checkbox neboli zaškrtávací pole. 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ě:

app.addCheckBox("text checkboxu")

Stav zaškrtávacího tlačítka se zjišťuje metodou getCheckBox(), které se předá text checkboxu. Vidíme tedy, že text se současně používá jako identifikátor widgetu. Dejte si tedy pozor na to, aby se v jednom okně či dialogu nevyskytl stejně pojmenovaný checkbox:

app.getCheckBox("text checkboxu")

Návratovou hodnotou této funkce je pravdivostní hodnota True či False.

V dalším demonstračním příkladu se po stlačení tlačítka Ok zobrazí stav obou zaškrtávacích polí. Povšimněte si, že můžeme bez problémů používat znaky Unicode; navíc dokáže infoBox zobrazit víceřádkový text.

Obrázek 6: Použití Unicode znaků ve víceřádkové zprávě.

Následuje zdrojový kód příkladu:

#!/usr/bin/env python
 
from appJar import gui
 
 
CHECK_SYMBOL = "\u2713"
MULTIPLY_SYMBOL = "\u2715"
 
 
def state(choice):
    return CHECK_SYMBOL if choice else MULTIPLY_SYMBOL
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "1st choice: {c1}\n2nd choice: {c2}".format(
            c1=state(app.getCheckBox("1st choice")),
            c2=state(app.getCheckBox("2nd choice")))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 10)
 
app.addCheckBox("1st choice", 1, 1)
app.addCheckBox("2nd choice", 2, 1)
app.addButton("Show choices", onButtonPress, 3, 1)
app.addButton("Quit", onButtonPress, 3, 2)
 
app.go()

Obrázek 7: Screenshot dnešního třetího demonstračního příkladu.

6. Konfigurace zaškrtávacích polí

Metodou setCheckBox() je možné nastavit ta zaškrtávací pole, která mají být implicitně vybrána:

app.setCheckBox("1st choice", ticked=True)

Navíc je možné explicitně zavolat funkci navázanou na příslušný widget (tímto tématem jsme se však ještě nezabývali):

app.setCheckBox("1st choice", callFunction=True)

V následujícím demonstračním příkladu je po jeho spuštění implicitně vybráno první zaškrtávací pole:

#!/usr/bin/env python
 
from appJar import gui
 
 
CHECK_SYMBOL = "\u2713"
MULTIPLY_SYMBOL = "\u2715"
 
 
def state(choice):
    return CHECK_SYMBOL if choice else MULTIPLY_SYMBOL
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "1st choice: {c1}\n2nd choice: {c2}".format(
            c1=state(app.getCheckBox("1st choice")),
            c2=state(app.getCheckBox("2nd choice")))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 10)
 
app.addCheckBox("1st choice", 1, 1)
app.addCheckBox("2nd choice", 2, 1)
 
app.setCheckBox("1st choice", ticked=True)
 
app.addButton("Show choices", onButtonPress, 3, 1)
app.addButton("Quit", onButtonPress, 3, 2)
 
app.go()

Obrázek 8: Screenshot dnešního čtvrtého demonstračního příkladu.

7. Přepínače (radio buttons)

Dalším velmi často používaným ovládacím prvkem (přesněji řečeno specializovanou variantou tlačítka) je takzvaný RadioButton (přepínač). Tento typ widgetu se od předchozích dvou typů tlačítek (Button a CheckBox odlišuje především tím, že je používán ve větších skupinách. Z každé skupiny přitom může být vybrán (nastaven) pouze jeden přepínač, od čehož je ostatně odvozen původní anglický název tohoto ovládacího prvku, protože připomíná přepínač kanálů na starších rádiích.

Skupina přepínačů se vytvoří jednoduše – postačuje jim nastavit shodný název, ale odlišný text (poslední dva parametry určují umístění widgetů do mřížky):

app.addRadioButton("languages", "Assembler", 1, 1)
app.addRadioButton("languages", "C", 2, 1)
app.addRadioButton("languages", "C++", 3, 1)
app.addRadioButton("languages", "Perl", 4, 1)
app.addRadioButton("languages", "Python", 5, 1)

Aktuálně vybraný přepínač se zjistí snadno metodou getRadioButton(). V našem konkrétním případě tedy:

volba = app.getRadioButton("languages")

Návratovou hodnotou je text zobrazený vedle vybraného přepínače.

Podívejme se na jednoduchý příklad, v němž je použita jedna skupina pěti přepínačů:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice: {c}".format(c=app.getRadioButton("languages"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addRadioButton("languages", "Assembler", 1, 1)
app.addRadioButton("languages", "C", 2, 1)
app.addRadioButton("languages", "C++", 3, 1)
app.addRadioButton("languages", "Perl", 4, 1)
app.addRadioButton("languages", "Python", 5, 1)
 
app.addButton("Show choice", onButtonPress, 6, 1)
app.addButton("Quit", onButtonPress, 6, 2)
 
app.go()

Obrázek 9: Screenshot dnešního pátého demonstračního příkladu.

Obrázek 10: Zobrazení uživatelem vybraného přepínače.

8. Změna způsobu zobrazení přepínačů

Pokud metodou setRadioButton() nastavíme konfigurační parametr tick na False, dojde ke změne zobrazení přepínačů:

app.setRadioTick("languages", tick=False)

Přepínače se nyní podobají tlačítkům, z nichž vždy jen jedno je implicitně vybráno:

Obrázek 11: Změna způsobu zobrazení přepínačů metodou setRadioTick().

Příklad z předchozí kapitoly upravíme snadno:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice: {c}".format(c=app.getRadioButton("languages"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addRadioButton("languages", "Assembler", 1, 1)
app.addRadioButton("languages", "C", 2, 1)
app.addRadioButton("languages", "C++", 3, 1)
app.addRadioButton("languages", "Perl", 4, 1)
app.addRadioButton("languages", "Python", 5, 1)
 
app.setRadioTick("languages", tick=False)
 
app.addButton("Show choice", onButtonPress, 6, 1)
app.addButton("Quit", onButtonPress, 6, 2)
 
app.go()

Obrázek 12: Zobrazení vybraného přepínače.

9. Implicitně vybraný přepínač

Podobně jako u zaškrtávacích tlačítek je možné i u přepínačů vybrat ten přepínač, který je implicitně vybraný. V našem konkrétním případě můžeme s využitím metody setRadioButton() implicitně vybrat hodnotu/přepínač Python. Volání této metody je velmi snadné:

app.setRadioButton("languages", "Python")

Obrázek 13: Ihned po zobrazení hlavního okna je vybrán jazyk Python..

Upravený zdrojový kód demonstračního příkladu vypadá následovně:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice: {c}".format(c=app.getRadioButton("languages"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addRadioButton("languages", "Assembler", 1, 1)
app.addRadioButton("languages", "C", 2, 1)
app.addRadioButton("languages", "C++", 3, 1)
app.addRadioButton("languages", "Perl", 4, 1)
app.addRadioButton("languages", "Python", 5, 1)
 
app.setRadioButton("languages", "Python")
 
app.addButton("Show choice", onButtonPress, 6, 1)
app.addButton("Quit", onButtonPress, 6, 2)
 
app.go()

Obrázek 14: Zobrazení implicitně vybraného přepínače.

10. Seznam (listbox)

Při výběru z většího množství položek se stává použití přepínačů (RadioButton) neefektivní a většinou se namísto nich využívá další ovládací prvek nazvaný jednoduše ListBox neboli seznam (což je ovšem v kontextu programovacího jazyka Python poněkud matoucí název). Tento ovládací prvek umožňuje, aby uživatel vybral jednu či několik položek z prakticky libovolně dlouhého seznamu řetězců. Vzhledem k tomu, že seznam/listbox je ovládacím prvkem obsahujícím větší množství hodnot, pracuje se s ním dosti odlišným způsobem, než tomu bylo u přepínačů. Nejprve si ukažme, jakým způsobem se ListBox vytváří a jak se do něj vkládají jednotlivé řetězce (položky). Vše zajišťuje jediná metoda, které se předá jméno ovládacího prvku a seznam hodnot:

app.addListBox("listbox", ["Assembler", "C", "C++", "Perl", "Python"])

Obrázek 15: Seznam neboli listbox s pěti prvky.

Pro získání vybrané hodnoty použijeme:

value = app.getListItems("listbox"))

Tato metoda se skutečně jmenuje getListItems() a nikoli jen getListItem(). Navíc tato metoda vrací seznam hodnot, v tomto konkrétním případě jednoprvkový seznam. Důvod tohoto chování si vysvětlíme později.

Opět se podívejme na příklad, v němž je listbox použit:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice: {c}".format(c=app.getListItems("listbox"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addListBox("listbox", ["Assembler", "C", "C++", "Perl", "Python"])
 
app.addButton("Show choice", onButtonPress)
app.addButton("Quit", onButtonPress)
 
app.go()

Obrázek 16: Zobrazení prvku vybraného ze seznamu.

11. Seznam s možností výběru více prvků

Pokud ihned po vytvoření seznamu zavoláme následující metodu:

app.setListBoxMulti("listbox", True)

změní se chování seznamu, neboť z něho nyní bude možné vybrat větší množství prvků. Ostatně se můžeme podívat na další screenshot:

Obrázek 17: Seznam neboli listbox s pěti prvky. Listbox je nakonfigurován tak, by umožnil výběr většího množství prvků.

V případě, že zavoláme nám již známou metodu getListItems():

value = app.getListItems("listbox"))

vrátí tato metoda seznam všech vybraných prvků. Právě toto je hlavní důvod, proč je v názvu metody použit plurál:

Obrázek 18: Zobrazení všech tří prvků vybraných ze seznamu.

Opět si ukažme, jak bude vypadat upravený demonstrační příklad:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice: {c}".format(c=app.getListItems("listbox"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addListBox("listbox", ["Assembler", "C", "C++", "Perl", "Python"])
app.setListBoxMulti("listbox", True)
 
app.addButton("Show choice", onButtonPress)
app.addButton("Quit", onButtonPress)
 
app.go()

12. Rozbalovací seznam

Kromě klasického výběrového seznamu obsahuje knihovna appJar i velmi podobný ovládací prvek nazvaný rozbalovací seznam. Ten se vytváří metodou addOptionBox(), která má stejné parametry jako metoda addListBox():

app.addOptionBox("optionbox", ["Assembler", "C", "C++", "Perl", "Python"])

Vytvořený rozbalovací seznam vypadá z pohledu moderního desktopu trošku zvláštně:

Obrázek 19: Rozbalovací seznam (OptionBox).

Ukažme si příklad, v němž je rozbalovací seznam použit. Můžeme vidět, že se tento příklad prakticky neliší od předchozího příkladu, až na to, že používáme odlišný widget:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice: {c}".format(c=app.getOptionBox("optionbox"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addOptionBox("optionbox", ["Assembler", "C", "C++", "Perl", "Python"])
 
app.addButton("Show choice", onButtonPress)
app.addButton("Quit", onButtonPress)
 
app.go()

13. Widgety, které pracují se slovníkem stavů

Widgety, které jsme si prozatím popsali, pracovaly buď s jedinou hodnotou (vstupní textové pole, zaškrtávací pole) nebo se seznamem hodnot (ListBox, OptionBox). V knihovně appJar však najdeme i dva widgety, které pro reprezentaci svého stavu používají slovník (dictionary, dict). Jedná se o rozbalovací seznam umožňující výběr většího množství prvků a dále o widget nazvaný poněkud neobvykle Properties. První zmíněný widget vrací vybrané prvky ve formě slovníku, v němž je každý prvek klíčem a hodnotou je stav jeho výběru (True/False). Naproti tomu widget Properties používá slovník již při specifikaci těch prvků, které se mají v tomto widgetu zobrazit. Podrobnosti si řekneme v navazujících kapitolách.

14. Rozbalovací seznam s výběrem většího množství prvků

Rozbalovací seznam, v němž je možné vybrat větší množství prvků, se vytváří metodou addTickOptionBox(). Základní použití této metody vypadá následovně:

app.addTickOptionBox("optionbox", ["Assembler", "C", "C++", "Perl", "Python"])

Povšimněte si, že běžný rozbalovací seznam se vytváří prakticky stejně:

app.addOptionBox("optionbox", ["Assembler", "C", "C++", "Perl", "Python"])

Obrázek 20: Rozbalovací seznam s možností výběru více prvků (TickOptionBox) se podobá běžnému rozbalovacímu seznamu (OptionBox), ovšem u jednotlivých prvků je zobrazen příznak výběru (✓).

Jediným rozdílem je, že v prvním případě je možné prvky zaškrtávat.

Pokud zavoláme metodu:

app.getOptionBox("optionbox")

vrátí se slovník obsahující u jména každého prvku hodnotu True či False podle toho, zda byl prvek vybrán či nikoli:

Obrázek 21: Výsledek volání metody app.getOptionBox(„optionbox“).

15. Ukázka použití rozbalovacího seznamu s možností výběru více prvků

Následuje příklad použití rozbalovacího seznamu s možností výběru více prvků:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice: {c}".format(c=app.getOptionBox("optionbox"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addTickOptionBox("optionbox", ["Assembler", "C", "C++", "Perl", "Python"])
 
app.addButton("Show choice", onButtonPress)
app.addButton("Quit", onButtonPress)
 
app.go()

16. Widget se skupinou zaškrtávacích prvků

Poslední widget, který si dnes popíšeme, se jmenuje Properties. Ve skutečnosti se jedná o skupinu zaškrtávacích tlačítek, jenž je ovšem vytvořena jediným voláním metody addProperties():

app.addProperties("properties", {"Assembler": True,
                                 "C": True,
                                 "C++": False,
                                 "Perl": False,
                                 "Python": True})

Z ukázky je patrné, že se této metodě předává slovník s prvky (ty zde vystupují jako klíče slovníku), přičemž u každého prvku lze specifikovat, jestli má být implicitně vybrán či nikoli:

Obrázek 22: Widget pojmenovaný Properties.

Stav widgetu Properties se přečte metodou getProperties(), která taktéž vrací slovník:

values = app.getProperties("properties")

Obrázek 23: Stav widgetu Properties.

17. Ukázka použití skupiny zaškrtávacích prvků

Opět se podívejme na způsob použití widgetu Properties. Není to nic těžkého:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choices: {c}".format(c=app.getProperties("properties"))
        app.infoBox("Show choices:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addProperties("properties", {"Assembler": True,
                                 "C": True,
                                 "C++": False,
                                 "Perl": False,
                                 "Python": True})
 
app.addButton("Show choice", onButtonPress)
app.addButton("Quit", onButtonPress)
 
app.go()

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

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

Poznámka: pro úspěšné spuštění těchto příkladů musíte mít v aktuálním adresáři rozbalenou knihovnu appJar!. Podrobnosti jsme si řekli v předchozím článku.

19. Odkazy na Internetu

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