Hlavní navigace

Grafické uživatelské rozhraní v Pythonu: další možnosti nabízené widgety Text a ScrolledText

Pavel Tišnovský

V dnešním článku o knihovně Tkinter si popíšeme další možnosti, které jsou nabízené všestranným widgetem Text. Taktéž se zmíníme o rozšířené variantě tohoto widgetu, která se jmenuje ScrolledText.

Obsah

1. Grafické uživatelské rozhraní v Pythonu: další možnosti nabízené widgety Text a ScrolledText

2. Složitější příklad se styly textu

3. Obrázky BitmapImage a PhotoImage ve widgetu Text

4. Konfigurace tabulačních zarážek

5. Zarovnání textu na tabulačních zarážkách

6. Další vlastnosti řetězců vkládaných do widgetu Text

7. Automatické zvýraznění textu, nad nímž se nachází kurzor myši

8. Reakce na stisk vybraného tlačítka (tlačítek) myši nad částí textu

9. Další widgety vložené do widgetu Text

10. Přidání dalších widgetů (tlačítka, checkboxu…) do textu

11. Modul ScrolledText/tkinter.scrolledtext

12. Příklad použití modulu ScrolledText – varianta pro Python 2.x

13. Příklad použití modulu tkinter.scrolledtext – varianta pro Python 3.x

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

15. Odkazy na Internetu

1. Grafické uživatelské rozhraní v Pythonu: další možnosti – nabízené widgety Text a ScrolledText

V předchozí části seriálu o tvorbě grafického uživatelského rozhraní v Pythonu jsme se kromě jiného seznámili i se základními vlastnostmi widgetu nazvaného Text. Připomeňme si jen, že Text patří vedle již popsaného widgetu canvas k prakticky nejsložitějším a současně i nejflexibilnějším objektům, se kterými je možné v knihovně Tkinter pracovat. Ve své nejjednodušší podobě slouží tento widget k zobrazení víceřádkového textu. To však není zdaleka vše. Text je totiž možné sdružovat do bloků a každému bloku nastavit nějaké atributy, typicky font, velikost textu, barvu textu, styl znaků (tučně, kurzíva, podtrženě atd.). Kromě toho se každý blok může chovat jako hypertextový odkaz. Dále je možné text různě zarovnávat, přidávat do něj obrázky či další widgety atd.

Obrázek 1: Nejjednodušší forma widgetu Text.

Dnes se seznámíme s dalšími možnostmi, které jsou tímto widgetem nabízeny. Nejprve si ukážeme složitější formátování textu, dále vkládání obrázků (bitmap i plnobarevných obrázků) do textu, konfiguraci tabulačních zarážek, které lze v případě potřeby použít pro zarovnání textu, a nezapomeneme ani na možnost zavolání zvoleného uživatelského kódu (většinou funkce či anonymní funkce) ve chvíli, kdy dojde k nějaké události. Na závěr se seznámíme s widgetem nazvaným ScrollText či scrolltext (podle použité verze Pythonu). Tento widget vlastně spojuje možnosti klasického scrollbaru s widgetem Text, a to velmi jednoduchým způsobem – celá konfigurace scrollbaru je totiž záležitostí jediného parametru.

2. Složitější příklad se styly textu

Kromě barev vykreslovaných řetězců je možné ve widgetu Text měnit i typ písma, což je ukázáno na dnešním prvním demonstračním příkladu. Zde si můžete všimnout, že vlastnosti underline (podtržení) a overstrike (přeškrtnutí, v příkladu není použito, sami si ho samozřejmě můžete vyzkoušet) se povolují a zakazují přiřazením logické hodnoty True/False. Přesná specifikace fontu je popsána na stránce http://www.tcl.tk/man/tcl8­.5/TkCmd/font.htm#M13, v naprosté většině případů si však vystačíme s řetězcem obsahujícím jméno fontu a jeho velikost, které mohou být alternativně doplněny o slovo „bold“ a/nebo „italic“ (obě slova lze zkombinovat, tedy například „„Helvetica 12 bold italic““). Kromě toho je možné font specifikovat n-ticí. Do textového widgetu je vložena i bitmapa, což je problematika, které se budeme podrobněji věnovat v navazující kapitole:

Obrázek 2: Text s různými styly i s vloženou bitmapou.

Následuje výpis zdrojového kódu první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()
 
image = tkinter.BitmapImage(file="test.xbm", foreground="white")
 
text = tkinter.Text(root,
                    font="Helvetica 20",
                    wrap=tkinter.WORD,
                    background="#202020",
                    width=40, height=16)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
 
# práce s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
text.insert(tkinter.END, "Cyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.image_create(tkinter.END, image=image)
text.insert(tkinter.END, "Brown\n", "brown")
text.insert(tkinter.END, "Pink\n", "pink")
text.insert(tkinter.END, "White\n", "white")
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

Poznámka: ještě bych rád připomenul, že u všech dnes popsaných demonstračních příkladů je zachována editovatelnost textu, nejedná se tedy o neživou část GUI, ale část aktivně komunikující s uživatelem.

3. Obrázky BitmapImage a PhotoImage ve widgetu Text

Mezi text umístěný na widgetu Text je možné vkládat obrázky, a to jak dvoubarevné obrázky, tak i obrázky vícebarevné. Postup je ve skutečnosti velmi jednoduchý – nejdříve obrázek načteme z externího datového souboru nebo z dat uložených přímo ve skriptu a následně obrázek vložíme do textu metodou text.image_create(), v níž specifikujeme jak bod vložení (například na konec textu), tak i vlastní obrázek. Samotný text přitom zůstává editovatelný; i samotné obrázky je možné mazat, posouvat atd.

Příklad vložení bitmapy, tedy dvoubarevného obrázku:

image = tkinter.BitmapImage(file="test.xbm", foreground="white")
 
text.image_create(tkinter.END, image=image)

Příklad vložení vícebarevného obrázku (buď s barvovou paletou či obrázku plnobarevného):

photo_image = tkinter.PhotoImage(file="icons/application-exit.gif")
 
text.image_create(tkinter.END, image=photo_image)

Následuje výpis zdrojového kódu demonstračního příkladu, v němž se používá jak objekt typu BitmapImage, tak i objekt typu PhotoImage:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
image = tkinter.BitmapImage(file="test.xbm", foreground="white")
photo_image = tkinter.PhotoImage(file="icons/application-exit.gif")
 
text = tkinter.Text(root,
                    font="Helvetica 20",
                    wrap=tkinter.WORD,
                    background="#202020",
                    width=40, height=16)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
 
# práce s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
text.insert(tkinter.END, "Cyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.image_create(tkinter.END, image=image)
text.insert(tkinter.END, "Brown\n", "brown")
text.insert(tkinter.END, "Pink    ", "pink")
text.image_create(tkinter.END, image=photo_image)
text.insert(tkinter.END, "White", "white")
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

Obrázek 3: Text s různými styly i s vloženou bitmapou i barevným obrázkem. Povšimněte si, že obrázek může být umístěn na stejném řádku s textem („x“).

4. Konfigurace tabulačních zarážek

Minule jsme si ukázali, jak se nastavují rozměry widgetu Text. Výška je specifikována v počtu textových řádků a šířka v počtu normoznaků odvozených od metriky fontu:

text = tkinter.Text(root,
                    width=40, height=16)

Kromě rozměrů widgetu je možné specifikovat i pozice tabulačních zarážek. Ty se zadávají pomocí pojmenované volby tabs, za níž následuje řetězec obsahující seznam značek. Seznam obsahuje pozice tabulačních zarážek; tyto pozice jsou chápány jako vzdálenosti zarážek od levého okraje widgetu. Pokud je za číslem udávajícím vzdálenost zapsán znak „c“, znamená to, že se vzdálenost bude počítat v šířkách normalizovaných znaků (což je většinou lepší, než se snažit o přepočet na pixely či na milimetry, i to je ale možné):

text = tkinter.Text(root,
                    font="Helvetica 20",
                    wrap=tkinter.WORD,
                    tabs="5c 11c 18c",
                    width=40, height=16)

Pozor na to, že použitý font může obsahovat (a většinou i obsahuje) proporcionální znaky a v některých případech nemusí výpočet šířky normalizovaných znaků proběhnout korektně – to je případ zejména různých sharewarových TrueType fontů, které někdy mají špatně vyplněnou tabulku s metrikami (tyto fonty se však nebudou chovat korektně ani v dalších aplikacích, navíc dnes pro Linux existují dostatečně kvalitní open source fonty).

V dalším demonstračním příkladu je vytvořen widget text, který bude mít rozměry 40×16 normoznaků. Přitom jsou nastaveny dvě tabulační zarážky. Povšimněte si, že znak tabulátoru se do řetězce zadává naprosto stejným způsobem jako v mnoha dalších programovacích jazycích (C, C++, Java, Perl):

text.insert(tkinter.END, "Mesic\tObrat\n", "nadpis")
text.insert(tkinter.END, "leden\t100\n")
...
...
...
text.insert(tkinter.END, "suma\t3900\n", "suma")

Některé řádky textu jsou zobrazeny jinou barvou a první řádek je podtržen. Toho bylo dosaženo vytvořením tagů nadpis a suma:

text.tag_configure("nadpis", foreground="red", underline=True)
text.tag_configure("suma", foreground="blue")

Obrázek 4: Text s tabulačními zarážkami použitými pro vytvoření jednoduché tabulky.

Následuje výpis zdrojového kódu 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()
 
text = tkinter.Text(root,
                    font="Helvetica 20",
                    wrap=tkinter.WORD,
                    tabs="5c 11c",
                    width=40, height=16)
 
text.tag_configure("nadpis", foreground="red", underline=True)
text.tag_configure("suma", foreground="blue")
 
text.insert(tkinter.END, "Mesic\tObrat\n", "nadpis")
text.insert(tkinter.END, "leden\t100\n")
text.insert(tkinter.END, "unor\t200\n")
text.insert(tkinter.END, "brezen\t0\n")
text.insert(tkinter.END, "duben\t1000\n")
text.insert(tkinter.END, "kveten\t100\n")
text.insert(tkinter.END, "cerven\t200\n")
text.insert(tkinter.END, "cervenec\t0\tdovolene\n")
text.insert(tkinter.END, "srpen\t1000\n")
text.insert(tkinter.END, "zari\t100\n")
text.insert(tkinter.END, "rijen\t200\n")
text.insert(tkinter.END, "listopad\t0\n")
text.insert(tkinter.END, "prosinec\t1100\tvanoce\n\n")
text.insert(tkinter.END, "suma\t3900\n", "suma")
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

5. Zarovnání textu na tabulačních zarážkách

Pokud se v seznamu s tabulačními zarážkami uvede jedno ze slov left, right, center nebo numeric, značí to způsob zarovnání textu vůči zarážce – zarovnání doleva, doprava, na střed a na desetinnou tečku/čárku (zarovnání na čárku bude funkční jen se správně nastavenou lokalizací). Tato funkce se chová stejně jako v textových procesorech. Například se podívejme na specifikaci zarovnání druhého sloupce doprava a třetího sloupce doleva (první sloupec samozřejmě začíná na levém okraji widgetu):

text = tkinter.Text(root,
                    font="Helvetica 20",
                    wrap=tkinter.WORD,
                    tabs="7c right 11c left",
                    width=40, height=16)

Obrázek 5: Text s tabulačními zarážkami se specifikovaným způsobem zarovnání jednotlivých sloupců „tabulky“.

Opět se podívejme na to, jak vypadá celý demonstrační příklad s widgetem Text a s nakonfigurovanými tabulačními zarážkami:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
text = tkinter.Text(root,
                    font="Helvetica 20",
                    wrap=tkinter.WORD,
                    tabs="7c right 11c left",
                    width=40, height=16)
 
text.tag_configure("nadpis", foreground="red", underline=True)
text.tag_configure("suma", foreground="blue")
 
text.insert(tkinter.END, "Mesic\tObrat\n", "nadpis")
text.insert(tkinter.END, "leden\t100\n")
text.insert(tkinter.END, "unor\t200\n")
text.insert(tkinter.END, "brezen\t0\n")
text.insert(tkinter.END, "duben\t1000\n")
text.insert(tkinter.END, "kveten\t100\n")
text.insert(tkinter.END, "cerven\t200\n")
text.insert(tkinter.END, "cervenec\t0\tdovolene\n")
text.insert(tkinter.END, "srpen\t1000\n")
text.insert(tkinter.END, "zari\t100\n")
text.insert(tkinter.END, "rijen\t200\n")
text.insert(tkinter.END, "listopad\t0\n")
text.insert(tkinter.END, "prosinec\t1100\tvanoce\n\n")
text.insert(tkinter.END, "suma\t3900\n", "suma")
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

Obrázek 6: Widget Text nemá problém ani se znaky s nabodeníčky.

6. Další vlastnosti řetězců vkládaných do widgetu Text

S využitím tagů je možné nastavit i další vlastnosti textových řetězců, které se vkládají do widgetu Text. Pro mnoho aplikací je důležité nastavení zarovnávání textů. To je možné obstarat buď pomocí výše zmíněných tabulačních zarážek (což je mnohdy zbytečně komplikované), nebo využitím vlastnosti justify. Této vlastnosti lze přiřadit více hodnot: tkinter.LEFT, tkinter.RIGHT a tkinter.CENTER (prozatím však není k dispozici možnost zarovnat text do bloku).

Dále je možné zvýraznit okraj okolo textu (funguje korektně i pro víceřádkový text, teoreticky se tak dají vytvořit jednodušší tabulky). Tento okraj může být opticky buď vysunutý nebo zasunutý (tkinter.RAISED, tkinter.SUNKEN).

Horní a dolní indexy se tvoří pomocí změny hodnoty vlastnosti offset, pomocí níž je možné text vertikálně posunout vůči textové osnově (kromě toho je vhodné text zmenšit o jeden až dva body, což je však již ponecháno na programátoru). Nastavení všech těchto vlastností je patrné z dalšího demonstračního příkladu, který rozšiřuje příklad předchozí:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
text = tkinter.Text(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=20)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
text.tag_configure("raised", relief=tkinter.RAISED, borderwidth=2)
text.tag_configure("sunken", relief=tkinter.SUNKEN, borderwidth=2)
text.tag_configure("center", justify=tkinter.CENTER)
text.tag_configure("left", justify=tkinter.LEFT)
text.tag_configure("right", justify=tkinter.RIGHT)
text.tag_configure("sup", offset="3p")
text.tag_configure("sub", offset="-3p")
 
 
# práce s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
text.insert(tkinter.END, "Cyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.insert(tkinter.END, "Brown\n", "brown")
text.insert(tkinter.END, "Pink\n", "pink")
text.insert(tkinter.END, "White\n", "white")
text.insert(tkinter.END, "Raised box\n", "raised")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Sunken box\n", "sunken")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Centered text\n", "center")
text.insert(tkinter.END, "Left justificiation\n", "left")
text.insert(tkinter.END, "Right justificiation\n", "right")
text.insert(tkinter.END, "H")
text.insert(tkinter.END, "2", "sub")
text.insert(tkinter.END, "O\n")
text.insert(tkinter.END, "E=mc")
text.insert(tkinter.END, "2", "sup")
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

Poznámka: stále se jedná o editovatelný text!

Obrázek 7: Různé styly textu, včetně horních a dolních indexů.

7. Automatické zvýraznění textu, nad nímž se nachází kurzor myši

Každý objekt vkládaný do widgetu Text (ať se jedná o textový řetězec, obrázek či o jiný widget), může reagovat na různé události. Vazba objektu na události se vytvoří pomocí příkazu tag_bind při konfiguraci tagu, který je či může být objektům přiřazen:

text.tag_bind(jméno_tagu, jméno_události, volaný_kód)

Mezi podporované události patří stisk či puštění libovolného tlačítka myši, posun kurzoru myši, přesun kurzoru myši nad objekt či opuštění hranic objektu atd. V dnešním šestém demonstračním příkazu je ukázáno, jak lze nakonfigurovat tag pojmenovaný colorOnEnter pomocí vazeb na dvě události. První událost nastane v případě, že je nad hranice objektu přesunut kurzor myši, druhá událost nastane ve chvíli opuštění hranic objektu kurzorem myši. Tyto události se nazývají Any-Enter a Any-Leave:

text.tag_bind("colorOnEnter", "<Any-Enter>",
              lambda e: text.tag_configure("colorOnEnter", background="red"))
 
text.tag_bind("colorOnEnter", "<Any-Leave>",
              lambda e: text.tag_configure("colorOnEnter", background=""))
 
text.insert(tkinter.END, "active-text", "colorOnEnter")

Obrázek 8: Aktivní text není zvýrazněn.

Obrázek 9: Zvýraznění pozadí „aktivního“ řetězce ve widgetu Text.

Následuje výpis zdrojového kódu šesté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()
 
text = tkinter.Text(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
text.tag_configure("raised", relief=tkinter.RAISED, borderwidth=2)
text.tag_configure("sunken", relief=tkinter.SUNKEN, borderwidth=2)
text.tag_configure("center", justify=tkinter.CENTER)
text.tag_configure("left", justify=tkinter.LEFT)
text.tag_configure("right", justify=tkinter.RIGHT)
text.tag_configure("sup", offset="3p")
text.tag_configure("sub", offset="-3p")
 
# chovani pri prejeti kurzorem mysi pres text
 
text.tag_bind("colorOnEnter", "<Any-Enter>",
              lambda e: text.tag_configure("colorOnEnter", background="red"))
text.tag_bind("colorOnEnter", "<Any-Leave>",
              lambda e: text.tag_configure("colorOnEnter", background=""))
 
# práce s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
text.insert(tkinter.END, "Cyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "active-text", "colorOnEnter")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.insert(tkinter.END, "Brown\n", "brown")
text.insert(tkinter.END, "Pink\n", "pink")
text.insert(tkinter.END, "White\n", "white")
text.insert(tkinter.END, "Raised box\n", "raised")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Sunken box\n", "sunken")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Centered text\n", "center")
text.insert(tkinter.END, "Left justificiation\n", "left")
text.insert(tkinter.END, "Right justificiation\n", "right")
text.insert(tkinter.END, "H")
text.insert(tkinter.END, "2", "sub")
text.insert(tkinter.END, "O\n")
text.insert(tkinter.END, "E=mc")
text.insert(tkinter.END, "2\n", "sup")
text.insert(tkinter.END, "active-text", "colorOnEnter")
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

8. Reakce na stisk vybraného tlačítka (tlačítek) myši nad částí textu

Nepatrným rozšířením zdrojového kódu popsaného v předchozí kapitole dosáhneme toho, že vybraný text či texty (s přiřazeným tagem colorOnEnter) budou reagovat na stisk tlačítek myši. Připomeňme si, že tlačítka myši jsou v knihovně Tkinter pojmenována takto:

Tlačítko Pojmenování události
levé <Button-1>
prostřední <Button-2>
pravé <Button-3>

Registrace handlerů událostí pro stisk levého a pravého tlačítka tedy může vypadat následovně:

text.tag_bind("colorOnEnter", "<Button-1>",
              lambda e: text.tag_configure("colorOnEnter", foreground="blue"))
text.tag_bind("colorOnEnter", "<Button-3>",
              lambda e: text.tag_configure("colorOnEnter", foreground="black"))

Obrázek 10: Stisk levého tlačítka myši změní barvu textu na modrou.

Obrázek 11: Stisk pravého tlačítka myši změní barvu textu zpět na černou.

Opět si ukažme celý příklad ve spustitelné formě:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
text = tkinter.Text(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
text.tag_configure("raised", relief=tkinter.RAISED, borderwidth=2)
text.tag_configure("sunken", relief=tkinter.SUNKEN, borderwidth=2)
text.tag_configure("center", justify=tkinter.CENTER)
text.tag_configure("left", justify=tkinter.LEFT)
text.tag_configure("right", justify=tkinter.RIGHT)
text.tag_configure("sup", offset="3p")
text.tag_configure("sub", offset="-3p")
 
# chovani pri prejeti kurzorem mysi
 
text.tag_bind("colorOnEnter", "<Any-Enter>",
              lambda e: text.tag_configure("colorOnEnter", background="red"))
text.tag_bind("colorOnEnter", "<Any-Leave>",
              lambda e: text.tag_configure("colorOnEnter", background=""))
 
# chovani pri stisku leveho a praveho tlacitka
 
text.tag_bind("colorOnEnter", "<Button-1>",
              lambda e: text.tag_configure("colorOnEnter", foreground="blue"))
text.tag_bind("colorOnEnter", "<Button-3>",
              lambda e: text.tag_configure("colorOnEnter", foreground="black"))
 
# práce s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
text.insert(tkinter.END, "Cyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "active-text", "colorOnEnter")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.insert(tkinter.END, "Brown\n", "brown")
text.insert(tkinter.END, "Pink\n", "pink")
text.insert(tkinter.END, "White\n", "white")
text.insert(tkinter.END, "Raised box\n", "raised")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Sunken box\n", "sunken")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Centered text\n", "center")
text.insert(tkinter.END, "Left justificiation\n", "left")
text.insert(tkinter.END, "Right justificiation\n", "right")
text.insert(tkinter.END, "H")
text.insert(tkinter.END, "2", "sub")
text.insert(tkinter.END, "O\n")
text.insert(tkinter.END, "E=mc")
text.insert(tkinter.END, "2\n", "sup")
text.insert(tkinter.END, "active-text", "colorOnEnter")
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

Obrázek 12: Zvýraznění textu po najetí kurzorem myši.

9. Další widgety vložené do widgetu Text

Do widgetu Text je možné kromě textových řetězců vkládat i další objekty a widgety. Všechny tyto objekty se vytváří pomocí oken vkládaných do textu. Na dalších dvou programových řádcích je ukázáno, jak se do textu vkládá widget typu button:

text = tkinter.Text(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)
 
text.insert(tkinter.END, "Brown\n", "brown")
 
button = tkinter.Button(root, text="Exit", command=exit)
text.window_create(tkinter.END, window=button)
 
text.insert(tkinter.END, "Pink\n", "pink")

Velmi flexibilní (ale v současné verzi Tkinteru stále problematické) je vložení plátna (canvasu) do textu nebo práce s obrázky – touto problematikou, která se často používá například při tvorbě prohlížečů dokumentace nebo nápovědy, se budeme zabývat v navazujících kapitolách.

10. Přidání dalších widgetů (tlačítka, checkboxu…) do textu

Pro zajímavost si ukažme, jakým způsobem se do widgetu Text vloží další ovládací prvky, zejména tlačítka, checkboxy a přepínače (radio buttony):

Obrázek 13: Další widgety vložené do textu.

Zdrojový kód příkladu:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
text = tkinter.Text(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
text.tag_configure("raised", relief=tkinter.RAISED, borderwidth=2)
text.tag_configure("sunken", relief=tkinter.SUNKEN, borderwidth=2)
text.tag_configure("center", justify=tkinter.CENTER)
text.tag_configure("left", justify=tkinter.LEFT)
text.tag_configure("right", justify=tkinter.RIGHT)
text.tag_configure("sup", offset="3p")
text.tag_configure("sub", offset="-3p")
 
# chovani pri prejeti kurzorem mysi
 
text.tag_bind("colorOnEnter", "<Any-Enter>",
              lambda e: text.tag_configure("colorOnEnter", background="red"))
text.tag_bind("colorOnEnter", "<Any-Leave>",
              lambda e: text.tag_configure("colorOnEnter", background=""))
 
# chovani pri stisku leveho a praveho tlacitka
 
text.tag_bind("colorOnEnter", "<Button-1>",
              lambda e: text.tag_configure("colorOnEnter", foreground="blue"))
text.tag_bind("colorOnEnter", "<Button-3>",
              lambda e: text.tag_configure("colorOnEnter", foreground="black"))
 
checkbutton = tkinter.Checkbutton(root, text="Delete Internet?",
                                  command=lambda: print("changed"))
 
quitButton = tkinter.Button(root, text="Exit", command=exit)
 
# práce s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
 
text.window_create(tkinter.END, window=checkbutton)
 
text.insert(tkinter.END, "\nCyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "active-text", "colorOnEnter")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.insert(tkinter.END, "Brown\n", "brown")
 
text.window_create(tkinter.END, window=quitButton)
 
text.insert(tkinter.END, "Pink\n", "pink")
text.insert(tkinter.END, "White\n", "white")
text.insert(tkinter.END, "Raised box\n", "raised")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Sunken box\n", "sunken")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Centered text\n", "center")
text.insert(tkinter.END, "Left justificiation\n", "left")
text.insert(tkinter.END, "Right justificiation\n", "right")
text.insert(tkinter.END, "H")
text.insert(tkinter.END, "2", "sub")
text.insert(tkinter.END, "O\n")
text.insert(tkinter.END, "E=mc")
text.insert(tkinter.END, "2\n", "sup")
text.insert(tkinter.END, "active-text", "colorOnEnter")
 
radio_var = tkinter.StringVar()
 
radio1 = tkinter.Radiobutton(root, variable=radio_var, value="Assembler",
                             text="Assembler")
 
radio2 = tkinter.Radiobutton(root, variable=radio_var, value="Basic",
                             text="Basic")
 
radio3 = tkinter.Radiobutton(root, variable=radio_var, value="Brainfuck",
                             text="Brainfuck")
 
radio4 = tkinter.Radiobutton(root, variable=radio_var, value="C",
                             text="C")
 
radio5 = tkinter.Radiobutton(root, variable=radio_var, value="Python",
                             text="Python")
 
text.insert(tkinter.END, "\nMaly vyber:\n")
text.window_create(tkinter.END, window=radio1)
text.window_create(tkinter.END, window=radio2)
text.window_create(tkinter.END, window=radio3)
text.window_create(tkinter.END, window=radio4)
text.window_create(tkinter.END, window=radio5)
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

11. Modul ScrolledText/tkinter.scrolledtext

K widgetu Text je samozřejmě možné připojit další widget představující scrollbar, ovšem konfigurace není v tomto případě příliš příjemná záležitost, neboť je nutné oba widgety správně umístit (stejná výška, variabilní šířka textu) a navíc i navázat scrollbar na widget Text (reakce na posun scrollbaru) a zajistit i zpětnou vazbu (posun kurzoru v textu nesmí vést k tomu, aby kurzor z okna zmizel). Aby se těmto zbytečným komplikacím zabránilo, byl vytvořen nový (doplňkový) „superwidget“ nazvaný ScrollText či scrolltext, podle toho, jakou verzi Pythonu aplikace bude používat. Už z odlišného pojmenování je patrné, že se nejedná o součást původní standardní sady widgetů knihovny Tkinter:

Obrázek 14: Doplňkový widget ScrollText.

12. Příklad použití modulu ScrolledText – varianta pro Python 2.x

Ve variantě aplikace používající widget ScrolledText, která je psaná pro Python 2.x, je zapotřebí provést následující kroky:

Import modulu (liší se od Pythonu 3.x!):

from ScrolledText import *

Konstrukce widgetu (jeho jméno se opět od Pythonu 3.x odlišuje):

text = ScrolledText(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)

Úplný zdrojový text příkladu:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
import sys
 
from ScrolledText import *
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
text = ScrolledText(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
text.tag_configure("raised", relief=tkinter.RAISED, borderwidth=2)
text.tag_configure("sunken", relief=tkinter.SUNKEN, borderwidth=2)
text.tag_configure("center", justify=tkinter.CENTER)
text.tag_configure("left", justify=tkinter.LEFT)
text.tag_configure("right", justify=tkinter.RIGHT)
text.tag_configure("sup", offset="3p")
text.tag_configure("sub", offset="-3p")
 
# chovani pri prejeti kurzorem mysi
 
text.tag_bind("colorOnEnter", "<Any-Enter>",
              lambda e: text.tag_configure("colorOnEnter", background="red"))
text.tag_bind("colorOnEnter", "<Any-Leave>",
              lambda e: text.tag_configure("colorOnEnter", background=""))
 
# chovani pri stisku leveho a praveho tlacitka
 
text.tag_bind("colorOnEnter", "<Button-1>",
              lambda e: text.tag_configure("colorOnEnter", foreground="blue"))
text.tag_bind("colorOnEnter", "<Button-3>",
              lambda e: text.tag_configure("colorOnEnter", foreground="black"))
 
def on_checkbutton():
    print "Changed"
 
checkbutton = tkinter.Checkbutton(root, text="Delete Internet?",
                                  command=on_checkbutton)
 
quitButton = tkinter.Button(root, text="Exit", command=exit)
 
# prace s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
 
text.window_create(tkinter.END, window=checkbutton)
 
text.insert(tkinter.END, "\nCyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "active-text", "colorOnEnter")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.insert(tkinter.END, "Brown\n", "brown")
 
text.window_create(tkinter.END, window=quitButton)
 
text.insert(tkinter.END, "Pink\n", "pink")
text.insert(tkinter.END, "White\n", "white")
text.insert(tkinter.END, "Raised box\n", "raised")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Sunken box\n", "sunken")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Centered text\n", "center")
text.insert(tkinter.END, "Left justificiation\n", "left")
text.insert(tkinter.END, "Right justificiation\n", "right")
text.insert(tkinter.END, "H")
text.insert(tkinter.END, "2", "sub")
text.insert(tkinter.END, "O\n")
text.insert(tkinter.END, "E=mc")
text.insert(tkinter.END, "2\n", "sup")
text.insert(tkinter.END, "active-text", "colorOnEnter")
 
radio_var = tkinter.StringVar()
 
radio1 = tkinter.Radiobutton(root, variable=radio_var, value="Assembler",
                             text="Assembler")
 
radio2 = tkinter.Radiobutton(root, variable=radio_var, value="Basic",
                             text="Basic")
 
radio3 = tkinter.Radiobutton(root, variable=radio_var, value="Brainfuck",
                             text="Brainfuck")
 
radio4 = tkinter.Radiobutton(root, variable=radio_var, value="C",
                             text="C")
 
radio5 = tkinter.Radiobutton(root, variable=radio_var, value="Python",
                             text="Python")
 
text.insert(tkinter.END, "\nMaly vyber:\n")
text.window_create(tkinter.END, window=radio1)
text.window_create(tkinter.END, window=radio2)
text.window_create(tkinter.END, window=radio3)
text.window_create(tkinter.END, window=radio4)
text.window_create(tkinter.END, window=radio5)
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

13. Příklad použití modulu tkinter.scrolledtext – varianta pro Python 3.x

Verze příkladu s widgetem tkinter.scrolledtext pro Python 3 má oproti předchozí variantě tyto rozdíly.

Odlišný modul pro import:

from tkinter.scrolledtext import *

Jiný konstruktor:

text = ScrolledText(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)

Zjednodušenou reakci (handler) na událost:

checkbutton = tkinter.Checkbutton(root, text="Delete Internet?",
                                  command=lambda: print("changed"))

Celý příklad vypadá takto:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
import sys
 
from tkinter.scrolledtext import *
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
text = ScrolledText(root,
                    font="Helvetica 14",
                    wrap=tkinter.WORD,
                    width=40, height=24)
 
text.tag_configure("underlined_red", foreground="red", underline=True)
text.tag_configure("big_green", foreground="green", font="Helvetica 40")
text.tag_configure("blue", foreground="blue")
text.tag_configure("magenta", foreground="magenta")
text.tag_configure("cyan", foreground="cyan")
text.tag_configure("small_yellow", foreground="yellow", font="Helvetica 10")
text.tag_configure("brown", foreground="brown")
text.tag_configure("pink", foreground="pink")
text.tag_configure("white", foreground="white", font="Courier 20")
text.tag_configure("raised", relief=tkinter.RAISED, borderwidth=2)
text.tag_configure("sunken", relief=tkinter.SUNKEN, borderwidth=2)
text.tag_configure("center", justify=tkinter.CENTER)
text.tag_configure("left", justify=tkinter.LEFT)
text.tag_configure("right", justify=tkinter.RIGHT)
text.tag_configure("sup", offset="3p")
text.tag_configure("sub", offset="-3p")
 
# chovani pri prejeti kurzorem mysi
 
text.tag_bind("colorOnEnter", "<Any-Enter>",
              lambda e: text.tag_configure("colorOnEnter", background="red"))
text.tag_bind("colorOnEnter", "<Any-Leave>",
              lambda e: text.tag_configure("colorOnEnter", background=""))
 
# chovani pri stisku leveho a praveho tlacitka
 
text.tag_bind("colorOnEnter", "<Button-1>",
              lambda e: text.tag_configure("colorOnEnter", foreground="blue"))
text.tag_bind("colorOnEnter", "<Button-3>",
              lambda e: text.tag_configure("colorOnEnter", foreground="black"))
 
checkbutton = tkinter.Checkbutton(root, text="Delete Internet?",
                                  command=lambda: print("changed"))
 
quitButton = tkinter.Button(root, text="Exit", command=exit)
 
# práce s widgetem
text.insert(tkinter.END, "Underlined Red\n", "underlined_red")
text.insert(tkinter.END, "Magenta\n", "magenta")
text.insert(tkinter.END, "Blue\n", "blue")
 
text.window_create(tkinter.END, window=checkbutton)
 
text.insert(tkinter.END, "\nCyan\n", "cyan")
text.insert(tkinter.END, "Big Green\n", "big_green")
text.insert(tkinter.END, "active-text", "colorOnEnter")
text.insert(tkinter.END, "Small Yellow\n", "small_yellow")
text.insert(tkinter.END, "Brown\n", "brown")
 
text.window_create(tkinter.END, window=quitButton)
 
text.insert(tkinter.END, "Pink\n", "pink")
text.insert(tkinter.END, "White\n", "white")
text.insert(tkinter.END, "Raised box\n", "raised")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Sunken box\n", "sunken")
text.insert(tkinter.END, "\n")
text.insert(tkinter.END, "Centered text\n", "center")
text.insert(tkinter.END, "Left justificiation\n", "left")
text.insert(tkinter.END, "Right justificiation\n", "right")
text.insert(tkinter.END, "H")
text.insert(tkinter.END, "2", "sub")
text.insert(tkinter.END, "O\n")
text.insert(tkinter.END, "E=mc")
text.insert(tkinter.END, "2\n", "sup")
text.insert(tkinter.END, "active-text", "colorOnEnter")
 
radio_var = tkinter.StringVar()
 
radio1 = tkinter.Radiobutton(root, variable=radio_var, value="Assembler",
                             text="Assembler")
 
radio2 = tkinter.Radiobutton(root, variable=radio_var, value="Basic",
                             text="Basic")
 
radio3 = tkinter.Radiobutton(root, variable=radio_var, value="Brainfuck",
                             text="Brainfuck")
 
radio4 = tkinter.Radiobutton(root, variable=radio_var, value="C",
                             text="C")
 
radio5 = tkinter.Radiobutton(root, variable=radio_var, value="Python",
                             text="Python")
 
text.insert(tkinter.END, "\nMaly vyber:\n")
text.window_create(tkinter.END, window=radio1)
text.window_create(tkinter.END, window=radio2)
text.window_create(tkinter.END, window=radio3)
text.window_create(tkinter.END, window=radio4)
text.window_create(tkinter.END, window=radio5)
 
button = tkinter.Button(root, text="Close window", command=exit)
 
text.pack()
button.pack()
 
root.mainloop()

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

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

Poznámka: poslední soubor test.xbm je bitmapou použitou v některých demonstračních příkladech. Tato bitmapa musí být umístěna ve stejném adresáři jako všechny příklady.

Obrázek 15: V poslední části článku o knihovně Tkinter se budeme zabývat mj. i problematikou tvorby dialogů.

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