Hlavní navigace

Tvorba grafického uživatelského rozhraní v Pythonu s využitím knihovny PySimpleGUI (4)

8. 2. 2024
Doba čtení: 37 minut

Sdílet

 Autor: Depositphotos
Dokončíme popis většiny zbývajících ovládacích prvků (widgetů) nabízených touto knihovnou i způsob jejich použití. Nyní už umíme tvořit i aplikace s poměrně sofistikovaným uživatelským rozhraním.

Obsah

1. Tvorba grafického uživatelského rozhraní v Pythonu s využitím knihovny PySimpleGUI (4)

2. Reakce prvků grafického uživatelského rozhraní na změnu velikosti okna

3. Reakce všech prvků na změnu velikosti okna

4. Zbylé ovládací prvky nabízené knihovnou PySimpleGUI

5. Spinbox

6. Slider (posuvník)

7. Další způsoby zobrazení slideru

8. ProgressBar: indikátor probíhající operace

9. Propojení posuvníku s progress barem

10. Výběrové menu (OptionMenu)

11. Výběr prvků ze seznamu (Listbox)

12. Statický rastrový obrázek

13. Data obrázku uložená přímo ve zdrojovém kódu

14. Animace

15. Složitější animace – vizualizace probíhající operace

16. Tabulka

17. Strom

18. Obsah poslední části seriálu o PySimpleGUI

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

20. Odkazy na Internetu

1. Tvorba grafického uživatelského rozhraní v Pythonu s využitím knihovny PySimpleGUI (dokončení)

Jak již bylo zmíněno v perexu, dokončíme dnes popis většiny zbývajících ovládacích prvků (widgetů) nabízených knihovnou PySimpleGUI i způsob jejich použití. S informacemi získanými ve všech čtyřech článcích (předchozí články najdete na [1] [2] a [3]) je možné tvořit i aplikace s poměrně komplikovaným uživatelským rozhraním – a přitom bude GUI část dosti jednoduchá a přehledná.

Poznámka: ještě ovšem budeme muset popsat způsob práce se stromy (tree) a taby. Jedná se o složitější, ovšem velmi užitečné ovládací prvky, které navíc v některých jiných knihovnách pro tvorbu grafického uživatelského rozhraní nenalezneme.

Obrázek 1: Nepatrně složitější aplikace s GUI, která je součástí samotného balíčku PySimpleGUI.

2. Reakce prvků grafického uživatelského rozhraní na změnu velikosti okna

Nejprve si ukažme, jakým způsobem mohou prvky grafického uživatelského rozhraní (tedy například tlačítka) reagovat na změnu velikosti okna. Prozatím víme, že mezi ovládací prvky je možné v případě potřeby vkládat „pružiny“ představované neviditelným objektem PySimpleGUI.Push, který dokáže zajistit, že se mezi prvky GUI vloží stejně velké mezery. Pružiny mohou být na jednotlivých řádcích umístěny zcela libovolně, což je ostatně patrné z následujícího kódu:

...
...
...
    [
        sg.Push(),
        sg.Button("Button1"),
        sg.Button("Button2"),
    ],
    [
        sg.Button("Button1"),
        sg.Push(),
        sg.Button("Button2"),
    ],
    [
        sg.Button("Button1"),
        sg.Button("Button2"),
        sg.Push(),
    ],
    [
        sg.Push(),
        sg.Button("Button1"),
        sg.Button("Button2"),
        sg.Push(),
    ],
    [
        sg.Push(),
        sg.Button("Button1"),
        sg.Push(),
        sg.Button("Button2"),
        sg.Push(),
    ],
...
...
...

Ovšem při změně velikosti okna zůstávají velikosti samotných prvků GUI nezměněné, pouze se více roztáhnou či naopak stlačí pružiny mezi nimi. Toto chování však není jediné možné, protože jednotlivé prvky se mohou zvětšovat či zmenšovat současně s okny (nejedná se sice o zcela obvyklé či očekáváné chování, ovšem v některých situacích se může hodit).

Nejprve ovšem musíme změnu velikosti oken povolit. To je ve skutečnosti velmi snadné, protože při vytváření okna můžeme konstruktoru PySimpleGUI.Window() předat nepovinný parametr resizable nastavený na logickou hodnotu True. V takovém případě bude možné měnit velikost okna, a to všemi dostupnými prostředky (záleží na okenním manažeru atd.):

window = sg.Window("Window #37", layout, size=(320, 260), resizable=True, finalize=True)

Dále musíme v seznamu obsahujícím všechny ovládací prvky explicitně uvést klíče těch prvků, u nichž budeme chtít modifikovat jejich chování. Příkladem může být „odesílací“ tlačítko vytvářené konstruktorem PySimpleGUI.Submit():

sg.Submit(key="foo")

Po vytvoření okna (viz výše uvedený konstruktor) změníme vlastnosti tlačítka s klíčem „foo“. Konkrétně se jedná o vlastnosti nazvané expand_x a expand_y, které určují, jestli se bude tlačítko zvětšovat ve směru x-ové osy a/nebo osy y-ové:

window["foo"].expand(expand_x=True, expand_y=True)

Výsledný skript bude vypadat takto:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [
        sg.Button("Button1"),
        sg.Button("Button2"),
    ],
    [
        sg.Push(),
        sg.Button("Button1"),
        sg.Button("Button2"),
    ],
    [
        sg.Button("Button1"),
        sg.Push(),
        sg.Button("Button2"),
    ],
    [
        sg.Button("Button1"),
        sg.Button("Button2"),
        sg.Push(),
    ],
    [
        sg.Push(),
        sg.Button("Button1"),
        sg.Button("Button2"),
        sg.Push(),
    ],
    [
        sg.Push(),
        sg.Button("Button1"),
        sg.Push(),
        sg.Button("Button2"),
        sg.Push(),
    ],
    [sg.Submit(key="foo")],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #37", layout, size=(320, 260), resizable=True, finalize=True)
window["foo"].expand(expand_x=True, expand_y=True)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Vyzkoušejme si chování tohoto skriptu:

Obrázek 2: Okno ve své výchozí velikosti 320×260 pixelů.

Obrázek 3: Po zvětšení okna se příslušně zvětší i odesílací tlačítko.

Obrázek 4: Po zmenšení okna se příslušně zmenší i odesílací tlačítko.

3. Reakce všech prvků na změnu velikosti okna

Samozřejmě nám nic nebrání v tom, abychom vytvořili okno či dialog, jehož všechny prvky budou reagovat na změnu velikosti okna/dialogu. V našem konkrétním příkladu se tlačítkům přiřadí celočíselný klíč (může se jednat o jakýkoli hashovatelný objekt), což nám umožní snadný průchod všemi ovládacími prvky grafického uživatelského rozhraní:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [
        sg.Button("Button1", key=1),
        sg.Button("Button2", key=2),
    ],
    [
        sg.Push(),
        sg.Button("Button1", key=3),
        sg.Button("Button2", key=4),
    ],
    [
        sg.Button("Button1", key=5),
        sg.Push(),
        sg.Button("Button2", key=6),
    ],
    [
        sg.Button("Button1", key=7),
        sg.Button("Button2", key=8),
        sg.Push(),
    ],
    [
        sg.Push(),
        sg.Button("Button1", key=9),
        sg.Button("Button2", key=10),
        sg.Push(),
    ],
    [
        sg.Push(),
        sg.Button("Button1", key=11),
        sg.Push(),
        sg.Button("Button2", key=12),
        sg.Push(),
    ],
    [sg.Submit(key=13)],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #38", layout, size=(320, 260), resizable=True, finalize=True)
 
for i in range(1, 14):
    window[i].expand(expand_x=True, expand_y=True)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Opět si vyzkoušejme chování tohoto skriptu:

Obrázek 5: Okno ve své výchozí velikosti 320×260 pixelů.

Obrázek 6: Po zvětšení okna se příslušně zvětší i všechna tlačítka.

Obrázek 7: Po zmenšení okna se příslušně zmenší i všechna tlačítka.

4. Zbylé ovládací prvky nabízené knihovnou PySimpleGUI

Knihovna PySimpleGUI nabízí programátorům několik desítek ovládacích prvků (widgetů). Kolik jich přesně je záleží na tom, nad jakou knihovnou je PySimpleGUI použita. Pokud se jedná o TkInter, což je výchozí volba, jsou dostupné následující ovládací prvky:

Text Column ProgressBar
Input Frame Table
Combo Tab Tree
OptionMenu TabGroup VerticalSeparator
Multiline Pane HorizontalSeparator
Output Graph StatusBar
Radio Slider Sizegrip
Checkbox Listbox Push
Spin Menu VPush
Button MenubarCustom Sizer
Image ButtonMenu  
Canvas Titlebar  
Poznámka: některé ovládací prvky jsou neviditelné a slouží především pro definici layoutu dialogu nebo okna. Jedná se zejména o tyto prvky: Push, VPush („pružiny“) a Sizer.

S některými ovládacími prvky jsme se seznámili v předchozích článcích. Mnohé z nich (Text, Combo, InputText, Checkbox, Radio a Submit, resp. Button) jsou použity v tomto příkladu:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Name", size=(8, 0)), sg.InputText(key="name")],
    [sg.Text("Surname", size=(8, 0)), sg.InputText(key="surname")],
    [
        sg.Text("Role", size=(8, 0)),
        sg.Combo(
            ["Administrator", "Maintainer", "Guest"],
            default_value="Guest",
            readonly=True,
            key="role",
        ),
    ],
    [
        sg.Text("Register e-mail", size=(8, 0)),
        sg.Checkbox("", default=True, key="register e-mail"),
    ],
    [
        sg.Text("Color theme", size=(8, 0)),
        sg.Radio("Light", "THEME", default=False, key="light_theme"),
        sg.Radio("Dark", "THEME", default=True, key="dark_theme"),
    ],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #9", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Obrázek 8: Některé ovládací prvky, s nimiž jsme se již setkali – neměnitelný text, vstupní textová pole, výběrový box (combobox), zatrhávací box (checkbox), radiová tlačítka (radio buttons) a samozřejmě běžné tlačítko pro potvrzení voleb provedených v dialogu.

Ovšem i některé další prvky již byly popsány, především pak Column, StatusBar, Menu, Frame a Canvas. S dalšími ovládacími prvky se seznámíme v navazujících kapitolách.

5. Spinbox

Ovládací prvek nazvaný Spinbox nebo jen Spin (možno volně přeložit jako číselník) je směsicí widgetu Entry a Scrollbaru. Pokud tomuto ovládacímu prvku předáme při jeho konstrukci n-tici s řetězci, bude možné provádět výběr libovolného řetězce z této n-tice s využitím zobrazených tlačítek se šipkami nahoru a dolů. A pokud je nastaven fokus na tento prvek, lze použít i kurzorové šipky přímo na klávesnici:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Spin"), sg.Spin(["Alpher", "Bethe", "Gamow",], s=(15, 2))],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #39", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

A takto bude spinbox vypadat v okně aplikace:

Obrázek 9: Spinbox zobrazený v okně aplikace.

Po potvrzení dialogu se vrátí aktuálně vybraná hodnota spinboxu:

Event:  Submit     Values:  {0: 'Alpher'}

To znamená, že je praktičtější si spinbox pojmenovat:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Spin"), sg.Spin(["Alpher", "Bethe", "Gamow",], s=(15, 2), key="Author")],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #39", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

S výsledkem po stisku tlačítka Submit:

Event:  Submit     Values:  {'Author': 'Bethe'}

6. Slider (posuvník)

Slider je speciální forma posuvníku (scrollbar) určeného pro specifikaci numerické hodnoty s tím, že je hodnota vizuálně zobrazena (umístěna) na zvolené škále od-do. Předností posuvníku je fakt, že je u něj možné zobrazit značky představující zvolenou škálu hodnot a tak zrychlit změnu hodnot prováděnou uživatelem. Posuvník se vytváří konstruktorem PySimpleGUI.Slider, přičemž se v prvním parametru předá n-tice s minimální a maximální hodnotou. Zadat lze i orientaci a popř. i další parametry:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Slider"), sg.Slider((0, 10), orientation='h', s=(20, 15), key="slider")],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #41", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

A takto by se měl posuvník (slider) zobrazit v okně:

Obrázek 10: Slider zobrazený v okně aplikace.

Po potvrzení dialogu či uzavření okna je hodnotou objektu typu posuvník pochopitelně vybraná hodnota:

Event:  Submit     Values:  {'slider': 2.0}

7. Další způsoby zobrazení slideru

Velmi užitečné je zobrazení hodnot na slideru. Pro tento účel je nutné použít nepovinný parametr nazvaný tick_interval, kterému se předá krok mezi jednotlivými hodnotami. Takový slider je ovšem pochopitelně vyšší, popř. širší, v závislosti na jeho orientaci:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Slider"),
     sg.Slider((0, 10), orientation='h', tick_interval=1, s=(20, 15), key="slider")],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #42", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Výsledkem bude takto vypadající dialog:

Obrázek 11: Slider i s hodnotami na pravítku.

Taktéž je možné změnit orientaci slideru (i když vertikální orientace je málo používaná):

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Slider"),
     sg.Slider((0, 10), orientation='v', tick_interval=1, s=(20, 15), key="slider")],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #43", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Výsledek:

Obrázek 12: Vertikálně orientovaný slider.

A pochopitelně je možné dopředu zvolit hodnotu, která bude vybrána:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Slider"),
     sg.Slider((0, 10), orientation='h', tick_interval=1, s=(20, 15), default_value=7, key="slider")],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #44", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

8. ProgressBar: indikátor probíhající operace

Dalším často využívaným ovládacím prvkem je indikátor probíhající operace („teploměr“), který se nazývá ProgressBar. Při konstrukci tohoto prvku je nutné zvolit minimálně jeho maximální hodnotu a volitelně pak rozměry, orientaci (horizontální, vertikální), jméno atd. Změna teploměru, tedy typicky posun o další políčko směrem ke konci, se provádí metodou UpdateBar.

V demonstračním příkladu je nutno desetkrát kliknout na tlačítko Next step, aby „teploměr“ došel ke svému konci. Po jedenáctém výběru tohoto tlačítka je skript ukončen:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.ProgressBar(10, orientation="h", size=(20, 20), key="progress")],
    [sg.Button("Next step")],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #45", layout)
progress_bar = window["progress"]
 
# obsluha smyčky událostí (event loop)
for i in range(11):
    # přečtení události
    event, values = window.read()
    print("Event: ", event, "    Values: ", values)
    progress_bar.UpdateBar(i+1)
 
    # reakce na událost "uzavření okna"
    if event == sg.WIN_CLOSED:
        break
 
# po přečtení události okno zavřeme
window.close()

Obrázek 13: Dialog ihned po svém zobrazení.

Obrázek 14: Situace po několika kliknutích na tlačítko Next step.

Obrázek 15: Po dalším výběru tlačítka Next step se dialog uzavře a skript se ukončí.

9. Propojení posuvníku s progress barem

V dalším demonstračním příkladu si můžeme otestovat propojení posuvníku s „teploměrem“. Po každé změně pozice značky na posuvníku se příslušným způsobem změní i indikátor míry dokončení úkolu na „teploměru“. Přečtení hodnoty posuvníku a změna progress baru je pochopitelně provedena ve smyčce pro obsluhu událostí (viz zvýrazněnou dvojici řádků):

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Slider((0, 10), orientation='h', tick_interval=1, s=(25, 15), default_value=0, key="slider")],
    [sg.ProgressBar(10, orientation="h", size=(20, 20), key="progress")],
    [sg.Button("Update")],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #46", layout)
progress_bar = window["progress"]
slider = window["slider"]
 
# obsluha smyčky událostí (event loop)
while True:
    # přečtení události
    event, values = window.read()
    print("Event: ", event, "    Values: ", values)
 
    # reakce na událost "uzavření okna"
    if event == sg.WIN_CLOSED:
        break
 
    # změna hodnoty na progress baru
    value = values["slider"]
    progress_bar.UpdateBar(value)
 
# po přečtení události okno zavřeme
window.close()

Výsledný dialog se bude chovat následovně:

Obrázek 16: Progress bar ukazuje stejnou hodnotu, jaká je vybrána posuvníkem.

Obrázek 17: Progress bar ukazuje stejnou hodnotu, jaká je vybrána posuvníkem.

Obrázek 18: Progress bar ukazuje stejnou hodnotu, jaká je vybrána posuvníkem.

10. Výběrové menu (OptionMenu)

Poměrně netypickým ovládacím prvkem je výběrové menu. To lze považovat za obdobu list boxu (viz navazující kapitolu), ovšem výběrové menu je zobrazeno odlišným způsobem – jedná se vlastně o kombinaci tlačítka s kontextovým menu. Tento neobvyklý ovládací prvek je navíc dostupný jen v případě, pokud se pro správu GUI používá knihovna TkInter.

Podívejme se tedy jen v krátkosti na to, jak se tento prvek zařazuje do dialogů:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Option menu"),
     sg.OptionMenu(["Alpher", "Bethe", "Gamow",], s=(15, 2))],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #47", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Obrázek 19: Po výběru prvku OptionMenu se vlastně zobrazí kontextové menu. To je považováno za samostatné okno, proto je tento screenshot „uříznutý“.

11. Výběr prvků ze seznamu (Listbox)

V případě, že je zapotřebí dát uživatelům na výběr z několika pevně zadaných hodnot, je pravděpodobně nejjednodušší a nejpřehlednější použít radiová tlačítka, s nimiž jsme se již seznámili v předchozích článcích. Pokud je hodnot mnoho nebo se mohou měnit, je většinou vhodnější použít výběr ze seznamu (listbox), popř. výše zmíněné výběrové menu (to za předpokladu, že chcete využít dnes již méně známé ovládací prvky). Samotný seznam (listbox) je používanější a známější; proto ho pravděpodobně budete preferovat.

Při konstrukci listboxu je pouze nutné konstruktoru předat sekvenci s prvky, které se mají zobrazit. Dále lze zvolit velikost seznamu a popř. povolit či naopak zakázat zobrazení scrollbaru ve chvíli, kdy nelze na dané ploše zobrazit všechny jeho prvky. Ukažme si ten nejjednodušší způsob použití:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Text("Option menu"),
     sg.Listbox(["Alpher", "Bethe", "Gamow",], s=(20, 3))],
    [sg.Submit()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #48", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Výsledný dialog může vypadat následovně:

Obrázek 20: Dialog s výběrovým boxem se seznamem hodnot.

12. Statický rastrový obrázek

Další element grafického uživatelského rozhraní, který si popíšeme, je velmi jednoduchý. Jedná se o statický rastrový obrázek, který lze načíst z externího souboru a umístit ho do zvoleného místa na dialogu (například ve formě ikony atd.). Podporována je většina formátů rastrových obrázků vhodných pro ikony, tedy primárně GIF a PNG. Přidání obrázku do dialogu je triviální, jak je to ostatně patrné i při pohledu na následující zdrojový kód:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Image("globe.png")],
    [sg.Push(), sg.Submit(), sg.Push()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #49", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Obrázek zobrazený v dialogovém okně bude vypadat následovně:

Obrázek 21: Ikona zobrazená v dialogovém okně.

13. Data obrázku uložená přímo ve zdrojovém kódu

Samotný obrázek se většinou načítá z externích souborů, ovšem v případě potřeby lze malé ikony atd. mít uložené přímo ve zdrojovém kódu Pythonu. V takovém případě se původní obrázek převede (například nástrojem base64) do sekvence znaků podle kódování Base64 a výsledek se uloží jako hodnota typu bytes. To je v Pythonu snadné, protože stačí tuto hodnotu reprezentovat literálem zapisovaným takto:

b"hodnoty bajtů"

Díky použití Base64 se v takovém literálu nenachází žádné speciální (řídicí) znaky.

Předchozí demonstrační příklad tedy můžeme upravit do poněkud rozsáhlé podoby (schválně ho uvádím celý, aby bylo patrné, že zdrojové kódy mohou být obrovské):

import PySimpleGUI as sg
 
image=b"""
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
"""
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Image(image)],
    [sg.Push(), sg.Submit(), sg.Push()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #52", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

14. Animace

Do dialogů lze vložit i animované GIFy. Stále se bude jednat o widget typu Image, navíc způsob přepínání snímků v animovaném GIFu je možné řídit programově, konkrétně zavoláním metody UpdateAnimation. Příkladem může být skript, v němž se snímek změní po každém stisku tlačítka Next frame. Samotný animovaný GIF přitom obsahuje pouze dvojici snímků a vypadá následovně:

Obrázek 22: Animovaný GIF se dvěma snímky vložený do dialogu.

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Push(), sg.Image("blink.gif", key="gif"), sg.Push()],
    [sg.Push(), sg.Button("Next frame"), sg.Push()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #50", layout)
gif = window["gif"]
 
# obsluha smyčky událostí (event loop)
while True:
    # přečtení události
    event, values = window.read()
    print("Event: ", event, "    Values: ", values)
    if event == "Next frame":
        gif.UpdateAnimation("blink.gif")
 
    # reakce na událost "uzavření okna"
    if event == sg.WIN_CLOSED:
        break
 
 
# po přečtení události okno zavřeme
window.close()

A takto vypadá výsledný dialog:

Obrázek 23: Dialog s animovaným GIFem.

Obrázek 24: Dialog s animovaným GIFem po přepnutí snímku.

15. Složitější animace – vizualizace probíhající operace

V některých situacích je nutné vizuálně ukázat, že probíhá nějaká operace, ovšem ne vždy je možné použít již popsaný ProgressBar, protože nemusí být dopředu jasné, kolik kroků či jaký čas je nutný pro dokončení operace. V takovém případě si můžeme vypomoci animací, která vlastně neneznačuje, kdy se nějaká činnost dokončí. Můžeme použít například tento animovaý GIF:

Obrázek 25: Animovaný GIF naznačující probíhající operaci.

V dialogu navíc čekáme na přijetí události jen po specifikovanou dobu. V případě, že událost nebude do tohoto okamžiku přijata, pouze se přepne další snímek animace a opět se počká na další událost. Tím je zajištěno (i bez nutnosti použití čítače), že se budou jednotlivé snímky animace automaticky přepínat:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Push(), sg.Image("progress.gif", key="gif"), sg.Push()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #51", layout)
gif = window["gif"]
 
# obsluha smyčky událostí (event loop)
while True:
    # přečtení události
    event, values = window.read(timeout=50)
    print("Event: ", event, "    Values: ", values)
    gif.UpdateAnimation("progress.gif")
 
    # reakce na událost "uzavření okna"
    if event == sg.WIN_CLOSED:
        break
 
 
# po přečtení události okno zavřeme
window.close()

Výsledek bude vypadat takto:

Obrázek 26: Dialog s animovaným obrázkem.

Obrázek 27: Dialog s animovaným obrázkem.

16. Tabulka

Předposledním ovládacím prvkem grafického uživatelského rozhraní, se kterým se v dnešním článku setkáme, je tabulka. Data tabulky jsou reprezentována formou vnořených n-tic, seznamů, atd. První řádek dat ve výchozím nastavení označuje nadpisy sloupců, to je však možné v případě potřeby změnit. Podívejme se nyní na způsob zobrazení jednoduché tabulky:

import PySimpleGUI as sg
 
data = [
        ["Jan 2024", "Jan 2023", "Language", "Ratings", "Change"],
        [1, 1, "Python", "13.97%", "-2.39%"],
        [2, 2, "C", "11.44%", "-4.81%"],
        [3, 3, "C++", "9.96%", "-2.95%"],
        [4, 4, "Java", "7.87%", "-4.34%"],
        [5, 5, "C#", "7.16%", "+1.43%"],
        [6, 7, "JavaScript", "2.77%", "-0.11%"],
        ]
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [sg.Table(data)],
    [sg.Push(), sg.Submit(), sg.Push()],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #53", layout)
 
# přečtení jediné události
event, values = window.read()
print("Event: ", event, "    Values: ", values)
 
# po přečtení události okno zavřeme
window.close()

Výsledkem bude tento dialog:

Obrázek 28: Tabulka zobrazená v dialogu.

17. Strom

Dalším typem ovládacího prvku grafického uživatelského rozhraní jsou stromy tree. Jedná se o jediný prvek GUI, u kterého neexistuje jednoduše zapsatelný konstruktor. Namísto toho je nutné stromy konstruovat programově, od kořenového uzlu k listům stromu (root, leaf. Do stromu se uzly přidávají metodou:

data.Insert("klíč předka", "klíč", "jméno uzlu", [hodnoty])

Pro uzly navázané přímo na kořenový uzel se namísto klíče předka používá prázdný řetězec.

Příklad stromu se třemi uzly navázanými na kořenový uzel. Každý z těchto uzlů má tři potomky (které jsou přímo koncovými uzly):

DT24

data = sg.TreeData()
 
#         předek  klíč  jméno  hodnoty
data.Insert("",   "A",  "A",   [])
data.Insert("",   "B",  "B",   [])
data.Insert("",   "C",  "D",   [])
data.Insert("A",  "A1", "A1",  [])
data.Insert("A",  "A2", "A2",  [])
data.Insert("A",  "A3", "A3",  [])
data.Insert("B",  "B1", "B1",  [])
data.Insert("B",  "B2", "B2",  [])
data.Insert("B",  "B3", "B3",  [])
data.Insert("C",  "C1", "C1",  [])
data.Insert("C",  "C2", "C2",  [])
data.Insert("C",  "C3", "C3",  [])

18. Obsah poslední části seriálu o PySimpleGUI

V navazující a současně i poslední části seriálu o knihovně PySimpleGUI nejprve dokončíme popis tabulek a stromů, což jsou nejsložitější elementy grafického uživatelského rozhraní. A posléze si popíšeme i práci s taby, které využijeme ve složitějších typech dialogů.

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

Všechny Pythonovské skripty, které jsme si ukázali v úvodní trojici článků o PySimpleGUI a pochopitelně i v dnešním článku ukázali, naleznete na adrese https://github.com/tisnik/most-popular-python-libs. Následují odkazy na jednotlivé příklady. Pro jejich spuštění je nutné mít nainstalován balíček PySimpleGUI, jenž závisí na standardním balíčku TkInter:

# Příklad Stručný popis Adresa příkladu
1 01-empty-window.py prázdné okno https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/01-empty-window.py
2 02-empty-window-event-loop.py prázdné okno, implementace klasické smyčky událostí https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/02-empty-window-event-loop.py
3 03-window-with-text-label.py okno se specifikovanou velikostí a s vloženým textovým prvkem https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/03-window-with-text-label.py
4 04-window-with-text-label.py okno s automaticky vypočtenou velikostí a s vloženým textovým prvkem https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/04-window-with-text-label.py
5 05-more-controls.py pětice ovládacích prvků přidaných do okna https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/05-more-controls.py
6 06-info.py informační okno (dialog) bez navázané smyčky událostí https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/06-info.py
7 07-events.py tisk všech zaregistrovaných a přečtených událostí https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/07-events.py
8 08-events-cancel.py tisk zaregistrovaných událostí, reakce na stisk tlačítka Cancel https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/08-events-cancel.py
9 09-one-shot-window.py dialog pro zadání údajů do textových políček, bez smyčky událostí https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/09-one-shot-window.py
10 10-sizing.py explicitní nastavení velikostí jednotlivých ovládacích prvků https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/10-sizing.py
11 11-even-more-controls.py přidání dalších ovládacích prvků do okna https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/11-even-more-controls.py
12 12-different-theme.py nastavení odlišného barvového tématu https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/12-different-theme.py
13 13-print-themes.py tisk jmen všech dostupných témat https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/13-print-themes.py
14 14-print-themes-2.py tisk jmen všech dostupných témat, lepší varianta https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/14-print-themes-2.py
       
15 15-select-theme.py interaktivní změna tématu https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/15-select-theme.py
16 16-better-select-theme.py vylepšení předchozího příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/16-better-select-theme.py
17 17-default-alignment.py výchozí zarovnání ovládacích prvků https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/17-default-alignment.py
18 18-center-alignment.py horizontální vycentrování ovládacích prvků https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/18-center-alignment.py
19 19-right-alignment.py zarovnání ovládacích prvků doprava https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/19-right-alignment.py
20 20-push.py „pružiny“ použité při rozmístění prvků https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/20-push.py
21 21-columns.py umístění prvků do sloupců https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/21-columns.py
22 22-columns.py umístění prvků do sloupců, sloupce uvnitř sloupců https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/22-columns.py
23 23-separators.py horizontální a vertikální oddělovače https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/23-separators.py
24 24-frames.py umístění prvků do rámců https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/24-frames.py
25 25-menu.py hlavní menu v okně aplikace https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/25-menu.py
26 26-status-bar.py stavový řádek v okně aplikace https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/26-status-bar.py
27 27-custom-titlebar.py změna způsobu zobrazení titulkové lišty https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/27-custom-titlebar.py
28 28-context-menu.py kontextové menu https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/28-context-menu.py
29 29-canvas.py vytvoření kreslicího plátna https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/29-canvas.py
30 30-canvas-size-background.py specifikace velikosti plátna a barvy jeho pozadí https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/30-canvas-size-background.py
       
31 31-draw-on-canvas.py vykreslení úseček na plátno https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/31-draw-on-canvas.py
32 32-more-shapes.py ukázka většího množství geometrických tvarů https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/32-more-shapes.py
33 33-pieslice-and-chord.py kruhové výseče a úseče https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/33-pieslice-and-chord.py
34 34-arrows.py různé tvary šipek https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/34-arrows.py
35 35-line-styles.py styly vykreslování úseček https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/35-line-styles.py
36 36-line-dashes.py styly vykreslování úseček https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/36-line-dashes.py
       
37 37-resizable-window.py okno, jehož tlačítko reaguje na změnu velikosti okna https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/37-resizable-window.py
38 38-resizable-window-2.py okno, jehož všechna tlačítka reagují na změnu velikosti okna https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/38-resizable-window-2.py
39 39-spinbox.py ovládací prvek typu Spin/Spinbox https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/39-spinbox.py
40 40-named-spinbox.py pojmenovaný Spinbox, k jehož hodnotě se může přistupovat https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/40-named-spinbox.py
41 41-slider.py ovládací prvek typu posuvník https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/41-slider.py
42 42-slider-ticks.py zobrazení pravítka na posuvníku https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/42-slider-ticks.py
43 43-vertical-slider.py vertikálně orientovaný posuvník https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/43-vertical-slider.py
44 44-slider-init-value.py nastavení výchozí hodnoty posuvníku https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/44-slider-init-value.py
45 45-progress-bar.py indikátor probíhající operace https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/45-progress-bar.py
46 46-slider-and-progress-bar.py propojení posuvníku s indikátorem probíhající operace https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/46-slider-and-progress-bar.py
47 47-option-menu.py výběrové menu (OptionMenu) https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/47-option-menu.py
48 48-listbox.py výběr prvku ze seznamu (Listbox) https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/48-listbox.py
49 49-image.py zobrazení statického obrázku v dialogu https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/49-image.py
50 50-animated-gif.py animovaný GIF na formuláři https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/50-animated-gif.py
51 51-progress.py probíhající operace vizualizovaná animovaným GIFem https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/51-progress.py
52 52-static-image-in-sources.py statický obrázek umístěný přímo do zdrojových kódů https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/52-static-image-in-sources.py
53 53-table.py tabulka zobrazená v dialogovém okně https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/53-table.py
54 54-tree.py strom zobrazený v dialogovém okně https://github.com/tisnik/most-popular-python-libs/blob/master/PySimpleGUI/54-tree.py

20. Odkazy na Internetu

  1. PySimpleGUI
    https://www.pysimplegui.or­g/en/latest/
  2. Kivy na GitHubu
    https://github.com/kivy/kivy
  3. DearPyGui na GitHubu
    https://github.com/hoffstad­t/DearPyGui
  4. PySimpleGUI Tutorial
    https://www.tutorialspoin­t.com/pysimplegui/index.htm
  5. PySimpleGUI – Canvas Element
    https://www.tutorialspoin­t.com/pysimplegui/pysimple­gui_canvas_element.htm
  6. Dokumentace ke knihovně PySimpleGUI
    https://www.pysimplegui.or­g/en/latest/
  7. Dokumentace ke knihovně DearPyGui
    https://dearpygui.readthe­docs.io/en/latest/index.html#
  8. The Hitchhiker's Guide to Pyhton: GUI Applications
    http://docs.python-guide.org/en/latest/scenarios/gui/
  9. 7 Top Python GUI Frameworks for 2017
    http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/
  10. Stránky projektu wxPython
    https://wxpython.org/
  11. wxPython Project Phoenix (na GitHubu)
    https://github.com/wxWidget­s/Phoenix/blob/wxPython-4.0.3/README.rst
  12. wxPython API Documentation
    https://docs.wxpython.org/index.html
  13. wxWidgets
    https://wxwidgets.org/
  14. wxPython 4.0.3 na PyPi
    https://pypi.org/project/wxPyt­hon/4.0.3/
  15. wxGlade – a GUI builder for wxWidgets
    http://wxglade.sourceforge.net/
  16. Repositář projektu wxGlade
    https://github.com/wxGlade/wxGlade/
  17. wxGlade’s documentation
    http://wxglade.sourceforge­.net/docs/index.html
  18. Graphical User Interfaces (GUI)
    https://pythonspot.com/gui/
  19. wxPyWiki
    https://wiki.wxpython.org/FrontPage
  20. Getting started with wxPython
    https://wiki.wxpython.org/Get­ting%20Started#A_First_Ap­plication:_.22Hello.2C_Wor­ld.22
  21. wxPython GUI tutorial
    https://pythonspot.com/wxpython-gui-tutorial/
  22. wxPython tutorial
    http://zetcode.com/wxpython/
  23. Build wxPython On Raspberry Pi
    https://wiki.wxpython.org/Bu­ildWxPythonOnRaspberryPi
  24. wxPython History
    https://wxpython.org/pages/his­tory/index.html
  25. Installing wxPython 4.0 (Project Phoenix) on Fedora 27
    https://blog.wizardsofthe­web.pro/installing-wxpython-on-fedora/
  26. Category:Software that uses wxWidgets
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_wxWidgets
  27. Hra Breakout napísaná v Tkinteri
    https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/
  28. GUI Programming in Python
    https://wiki.python.org/mo­in/GuiProgramming
  29. Cameron Laird's personal notes on Python GUIs
    http://phaseit.net/claird/com­p.lang.python/python_GUI.html
  30. Python GUI development
    http://pythoncentral.io/introduction-python-gui-development/
  31. Hand Coded GUI Versus Qt Designer GUI
    https://stackoverflow.com/qu­estions/387092/hand-coded-gui-versus-qt-designer-gui
  32. Qt Creator Manual
    http://doc.qt.io/qtcreator/
  33. Qt Designer Manual
    http://doc.qt.io/qt-5/qtdesigner-manual.html
  34. Qt Creator (Wikipedia)
    https://en.wikipedia.org/wi­ki/Qt_Creator
  35. QIODevice
    https://pyside.github.io/doc­s/pyside/PySide/QtCore/QI­ODevice.html#PySide.QtCore­.QIODevice
  36. QFile
    https://pyside.github.io/doc­s/pyside/PySide/QtCore/QFi­le.html#PySide.QtCore.QFi­le
  37. QUiLoader
    https://pyside.github.io/doc­s/pyside/PySide/QtUiTools/QU­iLoader.html#PySide.QtUiTo­ols.PySide.QtUiTools.QUiLo­ader.load
  38. QSvgWidget
    https://pyside.github.io/doc­s/pyside/PySide/QtSvg/QSvgWid­get.html
  39. QByteArray
    https://pyside.github.io/doc­s/pyside/PySide/QtCore/QBy­teArray.html
  40. Differences Between PySide and PyQt
    https://wiki.qt.io/Differen­ces_Between_PySide_and_PyQt
  41. PySide 1.2.1 tutorials
    https://pyside.github.io/doc­s/pyside/tutorials/index.html
  42. PySide tutorial
    http://zetcode.com/gui/py­sidetutorial/
  43. Drawing in PySide
    http://zetcode.com/gui/py­sidetutorial/drawing/
  44. Qt Core
    https://pyside.github.io/doc­s/pyside/PySide/QtCore/Qt­.html
  45. Signals & Slots
    http://doc.qt.io/qt-4.8/signalsandslots.html
  46. Signals and Slots in PySide
    http://wiki.qt.io/Signals_an­d_Slots_in_PySide
  47. Intro to PySide/PyQt: Basic Widgets and Hello, World!
    http://www.pythoncentral.io/intro-to-pysidepyqt-basic-widgets-and-hello-world/
  48. Leo editor
    http://leoeditor.com/
  49. IPython Qt Console aneb vylepšený pseudoterminál
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-ipython-a-ipython-notebook/#k06
  50. Python GUI development
    http://pythoncentral.io/introduction-python-gui-development/
  51. Graphic User Interface FAQ
    https://docs.python.org/2/faq/gu­i.html#graphic-user-interface-faq
  52. TkInter
    https://wiki.python.org/moin/TkInter
  53. Tkinter 8.5 reference: a GUI for Python
    http://infohost.nmt.edu/tcc/hel­p/pubs/tkinter/web/index.html
  54. TkInter (Wikipedia)
    https://en.wikipedia.org/wiki/Tkinter
  55. appJar
    http://appjar.info/
  56. appJar (Wikipedia)
    https://en.wikipedia.org/wiki/AppJar
  57. appJar na Pythonhosted
    http://pythonhosted.org/appJar/
  58. appJar widgets
    http://appjar.info/pythonWidgets/
  59. Stránky projektu PyGTK
    http://www.pygtk.org/
  60. PyGTK (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  61. Stránky projektu PyGObject
    https://wiki.gnome.org/Pro­jects/PyGObject
  62. Stránky projektu Kivy
    https://kivy.org/#home
  63. Stránky projektu PyQt
    https://riverbankcomputin­g.com/software/pyqt/intro

Byl pro vás článek přínosný?