Hlavní navigace

Tvorba GUI v Pythonu s využitím knihovny PySimpleGUI (2)

2. 1. 2024
Doba čtení: 25 minut

Sdílet

 Autor: Depositphotos
Pro aplikace se složitějšími dialogy je nutné umět lépe rozmisťovat ovládací prvky na ploše oken a dialogů. K tomuto účelu slouží kontejnery, které si dnes popíšeme. Také si ukážeme způsob naprogramování reakce na události.

Obsah

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

2. Interaktivní výběr barevného tématu aplikace v GUI

3. Změna tématu ihned po jeho výběru z výběrového boxu

4. Výchozí zarovnání prvků v okně či kontejneru

5. Vycentrování prvků a zarovnání prvků doprava

6. Neviditelný prvek typu „pružina“

7. Další typ kontejneru – Column

8. Kontejnery je možné vložit do jiných kontejnerů

9. Vizuální oddělení GUI prvků

10. Rámce (Frame)

11. Přidání hlavního menu do okna aplikace

12. Přidání stavového řádku do okna aplikace

13. Vlastní způsob vykreslení titulku okna

14. Přidání kontextového menu

15. Kreslicí plátno (canvas)

16. Přidání kreslicího plátna do okna aplikace

17. Specifikace velikosti a barvy pozadí kreslicího plátna

18. Obsah navazujícího článku

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 (2)

V úvodním článku o knihovně PySimpleGUI jsme se dozvěděli, jak je možné vytvořit okno či dialog se základními prvky GUI. Ovšem pro tvorbu aplikací se složitějšími dialogy je nutné umět lépe rozmisťovat jednotlivé ovládací prvky na ploše oken a dialogů. K tomuto účelu slouží takzvané kontejnery, které si popíšeme dnes. Taktéž si ukážeme využití kreslicí plochy a v neposlední řadě i způsob naprogramování reakce na události, které vzniknou například ihned po výběru prvku ve výběrovém boxu (v takovém případě totiž PySimpleGUI ve výchozím nastavení žádnou událost nevytváří, což může být pro některé typy aplikací omezující).

2. Interaktivní výběr barevného tématu aplikace v GUI

Podívejme se nyní na způsob realizace výběru barevného tématu (ze všech dostupných témat) přímo z GUI aplikace. Je to relativně snadné. Nejdříve získáme jména všech témat postupem, který již známe z minula:

themes = sorted(sg.list_of_look_and_feel_values())

Posléze do okna aplikace vložíme ovládací GUI prvek Combo, nastavíme jeho jméno (resp. klíč), seznam všech témat a výchozí téma, které má být v prvku předvybrané:

sg.Combo(themes, default_value=selected_theme, readonly=True, key="theme")

A konečně ve smyčce událostí zajistíme, že když uživatel nějaké téma vybere a stiskne tlačítko Change, bude stávající okno zavřeno, změní se téma a vytvoří se okno nové:

# obsluha smyčky událostí (event loop)
while True:
    # přečtení události
    event, values = window.read()
 
    # reakce na výběr tématu
    if event == "Change":
        selected_theme = values["theme"]
        window.close()
        window = main_window(selected_theme)

Výsledky mohou vypadat takto:

Obrázek 1: Interaktivní výběr barevného tématu.

Obrázek 2: Interaktivní výběr barevného tématu.

Obrázek 3: Interaktivní výběr barevného tématu.

Pro úplnost si ukažme celý zdrojový kód demonstračního příkladu:

import PySimpleGUI as sg
 
themes = sorted(sg.list_of_look_and_feel_values())
 
 
# vytvoření okna s ovládacími prvky
def main_window(theme=None):
    selected_theme = theme or themes[0]
 
    # ovládací prvky, které se mají zobrazit v okně
    layout = [
        [
            sg.Text("Theme"),
            sg.Combo(themes, default_value=selected_theme, readonly=True, key="theme"),
        ],
        [
            sg.Button("Change"),
            sg.Cancel("Exit")
        ],
    ]
 
    sg.theme(selected_theme)
    return sg.Window("Window #4", layout)
 
 
window = main_window()
 
# obsluha smyčky událostí (event loop)
while True:
    # přečtení události
    event, values = window.read()
 
    # reakce na událost "uzavření okna"
    if event in {sg.WIN_CLOSED, "Exit"}:
        break
 
    # reakce na výběr tématu
    if event == "Change":
        selected_theme = values["theme"]
        window.close()
        window = main_window(selected_theme)
 
# po výskoku ze smyčky událostí aplikaci ukončíme
window.close()

3. Změna tématu ihned po jeho výběru z výběrového boxu

V demonstračním příkladu, který byl popsán v předchozí kapitole, bylo nutné téma nejdříve vybrat a poté stisknout tlačítko Change. To může být poněkud nepraktické, ovšem GUI prvek Combo ve svém výchozím nastavení negeneruje žádné události, takže je nutné generování událostí nejprve povolit. Ve skutečnosti je to velmi jednoduché, protože u tohoto ovládacího prvku postačí specifikace nepovinného parametru enable_events:

sg.Combo(themes, default_value=selected_theme, readonly=True, key="theme", enable_events=True)

Z okna odstraníme tlačítko Change (je už zbytečné) a upravíme smyčku událostí takovým způsobem, aby reagovala na událost „theme“ (což je jméno, resp. klíč kombo boxu):

# obsluha smyčky událostí (event loop)
while True:
    # přečtení události
    event, values = window.read()
 
    # reakce na událost "uzavření okna"
    if event in {sg.WIN_CLOSED, "Exit"}:
        break
 
    # reakce na výběr tématu
    if event == "theme":
        selected_theme = values["theme"]
        window.close()
        window = main_window(selected_theme)

Výsledky:

Obrázek 4: Interaktivní výběr barevného tématu upravenou aplikací.

Obrázek 5: Interaktivní výběr barevného tématu upravenou aplikací.

Obrázek 6: Interaktivní výběr barevného tématu upravenou aplikací.

Opět se pro úplnost podívejme na celý zdrojový kód takto upravené aplikace:

import PySimpleGUI as sg
 
themes = sorted(sg.list_of_look_and_feel_values())
 
 
# vytvoření okna s ovládacími prvky
def main_window(theme=None):
    selected_theme = theme or themes[0]
 
    # ovládací prvky, které se mají zobrazit v okně
    layout = [
        [
            sg.Text("Theme"),
            sg.Combo(themes, default_value=selected_theme, readonly=True, key="theme", enable_events=True),
        ],
        [
            sg.Cancel("Exit")
        ],
    ]
 
    sg.theme(selected_theme)
    return sg.Window("Window #4", layout)
 
 
window = main_window()
 
# obsluha smyčky událostí (event loop)
while True:
    # přečtení události
    event, values = window.read()
 
    # reakce na událost "uzavření okna"
    if event in {sg.WIN_CLOSED, "Exit"}:
        break
 
    # reakce na výběr tématu
    if event == "theme":
        selected_theme = values["theme"]
        window.close()
        window = main_window(selected_theme)
 
# po výskoku ze smyčky událostí aplikaci ukončíme
window.close()

4. Výchozí zarovnání prvků v okně či kontejneru

V případě, že budeme vytvářet layout složitějšího dialogu, je mnohdy nutné měnit i zarovnání prvků. Ve výchozím nastavení jsou prvky zarovnány doleva. To si můžeme velmi snadno otestovat spuštěním dalšího skriptu, který zobrazí čtyři GUI prvky (samá tlačítka), z nichž každý je umístěn na samostatném řádku. Jednotlivé prvky mají rozdílnou šířku, takže je jejich zarovnání zcela jasně patrné:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [
        sg.Button("S"),
    ],
    [
        sg.Button("Button"),
    ],
    [
        sg.Button("Long button"),
    ],
    [
        sg.Submit()
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #17", 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é okno by mělo vypadat následovně:

Obrázek 7: Okno se čtyřmi tlačítky zarovnanými doleva.

5. Vycentrování prvků a zarovnání prvků doprava

Zarovnání prvků není vlastností jednotlivých prvků, ale vlastností kontejneru, v nichž jsou prvky umístěny. My prozatím jako kontejner používáme celé okno aplikace, takže zarovnání bude muset být specifikováno zde. Pokusme se například prvky vycentrovat:

window = sg.Window("Window #18", layout, element_justification="c")

Výsledek by měl být odlišný:

Obrázek 8: Okno se čtyřmi tlačítky vycentrovanými tlačítky.

Celý skript vypadá takto:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [
        sg.Button("S"),
    ],
    [
        sg.Button("Button"),
    ],
    [
        sg.Button("Long button"),
    ],
    [
        sg.Submit()
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #18", layout, element_justification="c")
 
# 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()

Prvky samozřejmě můžeme nechat zarovnat doprava:

window = sg.Window("Window #18", layout, element_justification="r")

Tentokrát s tímto výsledkem:

Obrázek 9: Okno se čtyřmi tlačítky zarovnanými doprava.

A takto vypadá výsledný skript, který okno s GUI prvky vytvořil a zobrazil:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
layout = [
    [
        sg.Button("S"),
    ],
    [
        sg.Button("Button"),
    ],
    [
        sg.Button("Long button"),
    ],
    [
        sg.Submit()
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #18", layout, element_justification="r")
 
# 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()

6. Neviditelný prvek typu „pružina“

Kromě viditelných GUI prvků můžeme do okna (kontejneru) přidávat i některé neviditelné prvky. Důležitým prvkem je „pružina“ (Push), která od sebe odsouvá další prvky na stejném řádku. Pokud se na řádku použije více pružin, mají všechny stejnou sílu. To nám umožňuje například vycentrovat prvek tak, že před něj i za něj vložíme pružinu.

Pokusme se nyní na každý řádek vložit dvě tlačítka a vkládat mezi ně (na různé pozice) pružiny:

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()
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #20", layout, size=(320, 240))
 
# 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 by měly být takto rozmístěné prvky:

Obrázek 10: Tlačítka, mezi které jsou vkládány pružiny.

7. Další typ kontejneru – Column

Poměrně často je vhodné jednotlivé prvky grafického uživatelského rozhraní rozmístit do sloupců a nikoli do řádků. V knihovně PySimpleGUI sice pro tento účel nelze využít „mřížku“ (grid), ovšem programátoři mají k dispozici kontejner nazvaný jednoduše a příznačně Column. Díky tomu, že se jedná o kontejner, lze do něj vkládat další komponenty. Přitom se používá stále stejný koncept – komponenty jsou uloženy v dvourozměrném seznamu. Podívejme se, jak lze komponenty rozdělit do dvou sloupců:

left_column = [
    [první řádek komponent],
    [druhý řádek komponent],
    ...
]
 
right_column = [
    [první řádek komponent],
    [druhý řádek komponent],
    ...
]

Tyto sloupce se vloží na plochu okna stejně, jako jakékoli další komponenty. Pod sloupce je umístěn další řádek s tlačítkem:

layout = [
    [
        sg.Column(left_column),
        sg.Column(right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]

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

Obrázek 11: Komponenty rozmístěné do dvou sloupců.

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

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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"),
    ],
]
 
layout = [
    [
        sg.Column(left_column),
        sg.Column(right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #21", 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. Kontejnery je možné vložit do jiných kontejnerů

Kontejnery (kromě vlastních oken) mají jednu důležitou vlastnost – je možné je vkládat (i se všemi komponentami v nich) do dalších kontejnerů. To mj. znamená, že komponenta typu Column může být vložena do dalšího „sloupce“ atd. Tento koncept je ukázán na dalším demonstračním příkladu, kde v pravém sloupci je umístěn další sloupec s komponentami – radiovými tlačítky):

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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.Column([
            [sg.Radio("Light", "THEME", default=False, key="light_theme")],
            [sg.Radio("Dark", "THEME", default=True, key="dark_theme")],
        ]),
    ],
]
 
layout = [
    [
        sg.Column(left_column),
        sg.Column(right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #22", 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ý design okna:

Obrázek 12: Komponenty rozmístěné do dvou sloupců. V pravém sloupci je jako jedna z komponent umístěn ještě jeden sloupec.

9. Vizuální oddělení GUI prvků

Pro vizuální oddělení prvků grafického uživatelského rozhraní se používají horizontální a vertikální oddělovače (separátory), které jsou představovány pasivními komponentami HSep a VSep. V dalším demonstračním příkladu jsou použity oba typy separátorů tak, aby vzniklo okno s následujícím rozložením:

Obrázek 13: Horizontální a vertikální oddělovače (separátory).

Vertikální separátor je vložen mezi oba sloupce, horizontální separátor pak na samostatný řádek:

layout = [
    [
        sg.Column(left_column),
        sg.VSep(),
        sg.Column(right_column),
    ],
    [
        sg.HSep(),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]

Takto vypadá úplný zdrojový kód demonstračního příkladu, který oba typy oddělovačů používá:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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.Column([
            [sg.Radio("Light", "THEME", default=False, key="light_theme")],
            [sg.Radio("Dark", "THEME", default=True, key="dark_theme")],
        ]),
    ],
]
 
layout = [
    [
        sg.Column(left_column),
        sg.VSep(),
        sg.Column(right_column),
    ],
    [
        sg.HSep(),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #23", 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()

10. Rámce (Frame)

V případě, že se namísto kontejneru Column použije kontejner Frame, budou komponenty umístěné na tento kontejner orámovány. Navíc je možné každý pro každý rámec (frame) specifikovat jeho titulek, takže rozvržení celého okna (dialogu) můžeme realizovat i takto:

layout = [
    [
        sg.Frame("User", left_column),
        sg.Frame("Settings", right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]

S výsledkem:

Obrázek 14: Komponenty umístěné do rámců (frames).

A pro úplnost si ukažme úplný zdrojový kód takto upraveného demonstračního příkladu:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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.Column([
            [sg.Radio("Light", "THEME", default=False, key="light_theme")],
            [sg.Radio("Dark", "THEME", default=True, key="dark_theme")],
        ]),
    ],
]
 
layout = [
    [
        sg.Frame("User", left_column),
        sg.Frame("Settings", right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #24", 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()

11. Přidání hlavního menu do okna aplikace

Knihovna PySimpleGUI pochopitelně podporuje i specifikaci menu. Přímo na plochu okna (v jeho horní části, jak je zvykem) se umisťuje hlavní menu, které je realizováno komponentou nazvanou jednoduše Menu:

layout = [
    [sg.Menu(menu)],
    ...
    ...
    ...
]

Samotné menu je pak v tom nejjednodušším případě realizováno formou vnořeného seznamu. Jednotlivé podseznamy obsahují dva prvky: jméno příslušného rozbalovacího menu a druhým prvkem je další podseznam s jednotlivými položkami menu. Hlavní menu s dvojicí rozbalovacích menu může být definováno následovně:

menu = [
        ["File", ["New", "Open", "Save", "---", "Exit"]],
        ["Help", ["About"]],
        ]

Výsledné okno s hlavním menu může vypadat takto:

Obrázek 15: Okno aplikace s hlavním menu.

Celý zdrojový kód demonstračního příkladu s oknem a hlavním menu:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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.Column([
            [sg.Radio("Light", "THEME", default=False, key="light_theme")],
            [sg.Radio("Dark", "THEME", default=True, key="dark_theme")],
        ]),
    ],
]
 
menu = [
        ["File", ["New", "Open", "Save", "---", "Exit"]],
        ["Help", ["About"]],
        ]
 
layout = [
    [sg.Menu(menu)],
    [
        sg.Frame("User", left_column),
        sg.Frame("Settings", right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #25", 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()

12. Přidání stavového řádku do okna aplikace

Kromě hlavního menu se v aplikacích s grafickým uživatelským rozhraním mnohdy setkáme i s realizací stavového řádku. V knihovně PySimpleGUI je stavový řádek představován GUI komponentou nazvanou StatusBar, která v tom nejjednodušším případě bude obsahovat pouze nějaký text (ten lze později měnit). Typicky bývá stavový řádek umístěn v dolní části okna, tedy například takto:

layout = [
    [sg.Menu(menu)],
    [
        sg.Frame("User", left_column),
        sg.Frame("Settings", right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
    [sg.StatusBar("Status bar")],
]

Výsledek bude vypadat takto:

Obrázek 16: Okno aplikace s přidaným stavovým řádkem.

Opět nezapomeneme na úplný zdrojový kód aplikace s oknem, v němž je kromě dalších komponent použit i stavový řádek:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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.Column([
            [sg.Radio("Light", "THEME", default=False, key="light_theme")],
            [sg.Radio("Dark", "THEME", default=True, key="dark_theme")],
        ]),
    ],
]
 
menu = [
        ["File", ["New", "Open", "Save", "---", "Exit"]],
        ["Help", ["About"]],
        ]
 
layout = [
    [sg.Menu(menu)],
    [
        sg.Frame("User", left_column),
        sg.Frame("Settings", right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
    [sg.StatusBar("Status bar")],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #26", 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()

13. Vlastní způsob vykreslení titulku okna

Titulek okna (resp. přesněji řečeno oken) lze při použití knihovny PySimpleGUI vykreslit dvěma způsoby. Výchozí způsob využívá vlastnosti okenního manažeru (Window Manager), ovšem pokud při konstrukci okna použijeme parametr use_custom_titlebar nastavený na hodnotu True, bude vlastně vykresleno okno bez standardního titulkového pruhu. Ten bude následně vykreslen přímo v ploše okna knihovnou PySimpleGUI a bude tedy vypadat odlišně:

# vytvoření okna s ovládacími prvky
window = sg.Window("Window #27", layout, use_custom_titlebar=True)

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

Obrázek 17: Vlastní způsob vykreslení titulku okna.

Poznámka: v tomto případě je lepší se obejít bez hlavního menu. Navíc mohou mít některé okenní manažery problém s určením, které okno je právě aktivní (například při vytváření screenshotů).

A samozřejmě si ukážeme i úplný zdrojový kód příkladu:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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.Column([
            [sg.Radio("Light", "THEME", default=False, key="light_theme")],
            [sg.Radio("Dark", "THEME", default=True, key="dark_theme")],
        ]),
    ],
]
 
menu = [
        ["File", ["New", "Open", "Save", "---", "Exit"]],
        ["Help", ["About"]],
        ]
 
layout = [
    [sg.Menu(menu)],
    [
        sg.Frame("User", left_column),
        sg.Frame("Settings", right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
    [sg.StatusBar("Status bar")],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #27", layout, use_custom_titlebar=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()

14. Přidání kontextového menu

Další důležitou komponentou, především pro aplikace používané profesionály, je komponenta představující kontextové menu. Samotná definice kontextového menu je poněkud zvláštní, protože se typicky jedná o menu bez „rozbalovacího“ elementu. Proto se mnohdy setkáme s touto definicí:

context_menu = ["", ["About", "---", "Exit"]]

Kontextové menu se do okna aplikace přidá takto:

# vytvoření okna s ovládacími prvky
window = sg.Window("Window #28", layout, use_custom_titlebar=False, right_click_menu=context_menu)

Úplný zdrojový kód aplikace s kontextovým menu:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [
        sg.Text("Name", size=(8, 0)),
        sg.InputText(key="name", size=(20, 0))
    ],
    [
        sg.Text("Surname", size=(8, 0)),
        sg.InputText(key="surname", size=(20, 0))
    ],
]
 
right_column = [
    [
        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.Column([
            [sg.Radio("Light", "THEME", default=False, key="light_theme")],
            [sg.Radio("Dark", "THEME", default=True, key="dark_theme")],
        ]),
    ],
]
 
menu = [
        ["File", ["New", "Open", "Save", "---", "Exit"]],
        ["Help", ["About"]],
        ]
 
layout = [
    [sg.Menu(menu)],
    [
        sg.Frame("User", left_column),
        sg.Frame("Settings", right_column),
    ],
    [
        sg.Push(),
        sg.Submit(),
        sg.Push(),
    ],
    [sg.StatusBar("Status bar")],
]
 
context_menu = ["", ["About", "---", "Exit"]]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #28", layout, use_custom_titlebar=False, right_click_menu=context_menu)
 
# 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()

15. Kreslicí plátno (canvas)

Poměrně důležitou součástí knihovny PySimpleGUI je podpora kreslení grafických objektů na takzvané kreslicí plátno neboli canvas. Jedná se o techniku, která je do značné míry postavena na knihovně TkInter, v níž je podpora kreslicího plátna velmi sofistikovaná (a vlastně se těžko hledá její přímá obdoba či náhrada v jiných GUI toolkitech). V dalším textu (i v části třetího článku) se budeme tomuto tématu věnovat, protože v některých oblastech může být použití kreslicího plátna velmi užitečné.

16. Přidání kreslicího plátna do okna aplikace

Kreslicí plátno se z pohledu knihovny PySimpleGUI chová jako běžný prvek grafického uživatelského rozhraní. Vytváří se konstruktorem PySimpleGUI.Canvas a – jak uvidíme dále – můžeme při jeho konstrukci předat několik důležitých parametrů. Pokusme se ovšem pro začátek na plochu okna vložit kreslicí plátno vytvořené pouze zavoláním jeho konstruktoru, tj. bez předání dalších parametrů. Okno aplikace rozdělíme na levou a pravou část, přičemž plátno bude umístěno do pravé části:

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [sg.Button("Exit", size=(8, 0))],
]
 
right_column = [
    [
        sg.Canvas(),
    ],
]
 
layout = [
    [
        sg.Frame("Commands", left_column),
        sg.Frame("Canvas", right_column),
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #29", layout, use_custom_titlebar=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()

Výsledek by měl vypadat následovně:

Obrázek 18: Kreslicí plátno ve výchozí velikosti přidané na plochu okna.

17. Specifikace velikosti a barvy pozadí kreslicího plátna

U kreslicího plátna mnohdy budeme potřebovat specifikovat jeho rozměry. Na rozdíl od ostatních GUI komponent, jejichž velikosti se specifikují ve znacích (což je ovšem dosti vágní označení, které odpovídá logickým jednotkám „em“ a „x“), se rozměry plátna zadávají přímo v pixelech, což je pro tuto komponentu lepší řešení. A taktéž můžeme přímo specifikovat barvu pozadí plátna. Pro tento účel slouží nepovinný parametr nazvaný background_color:

sg.Canvas(background_color='white', size=(320, 240)),

Výsledek by měl vypadat takto:

Obrázek 19: Kreslicí plátno ve specifikované velikosti a se zadanou barvou pozadí přidané na plochu okna.

Úplný zdrojový kód dnešního posledního demonstračního příkladu vypadá následovně:

CS24 tip temata

import PySimpleGUI as sg
 
# ovládací prvky, které se mají zobrazit v okně
left_column = [
    [sg.Button("Exit", size=(8, 0))],
]
 
right_column = [
    [
        sg.Canvas(background_color='white', size=(320, 240)),
    ],
]
 
layout = [
    [
        sg.Frame("Commands", left_column),
        sg.Frame("Canvas", right_column),
    ],
]
 
# vytvoření okna s ovládacími prvky
window = sg.Window("Window #29", layout, use_custom_titlebar=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()

18. Obsah navazujícího článku

Ve třetím článku o knihovně PySimpleGUI se budeme zabývat převážně tím, jakým způsobem lze využít kreslicí plátno (canvas). Jedná se totiž o důležitou komponentu, která se používá například i pro tvorbu a vykreslení grafů, diagramů, různých složitějších struktur, ale i herního prostředí atd.

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

Všechny Pythonovské skripty, které jsme si v minulém i 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 pochopitelně nutné mít nainstalován balíček PySimpleGUI:

# 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

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

Autor článku

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