Obsah
1. Tvorba grafického uživatelského rozhraní v Pythonu s využitím knihovny Kivy: widgety
2. Jednodušší implementace aplikace s jediným oknem obsahujícím ovládací prvky
4. Ukázka naprogramování reakce na události: stisk nebo uvolnění tlačítka umístěného na dialogu
5. Základní ovládací prvky (widgety) dostupné v knihovně Kivy
6. Tlačítko se dvěma stavy – ToggleButton
7. Demonstrační příklad: dialog s tlačítkem se dvěma stavy
8. Zaškrtávací pole – Checkbox
9. Demonstrační příklad: dialog se zaškrtávacím polem
10. Několik na sobě nezávislých zaškrtávacích polí
12. Demonstrační příklad: zaškrtávací pole, které nepatří do jedné skupiny
13. Demonstrační příklad: přepínače vytvořené ze zaškrtávacích polí
15. Demonstrační příklad: posuvníky v dialogovém okně
16. Nastavení barvy ovládacích prvků
17. Vytvoření ikony z běžného tlačítka
18. Interaktivní nastavení barvy ovládacího prvku pomocí posuvníků
19. Repositář s demonstračními příklady
1. Tvorba grafického uživatelského rozhraní v Pythonu s využitím knihovny Kivy: widgety
Na úvodní článek o knihovně Kivy dnes navážeme. Připomeňme si, že Kivy je knihovna umožňující tvorbu aplikací s grafickým uživatelským rozhraním v Pythonu, přičemž tyto aplikace mohou být spouštěny jak na běžném desktopu (ovládaným klávesnicí a myší), tak například i na tabletech a chytrých telefonech s dotykovým ovládáním. Navíc knihovna Kivy podporuje specifikaci GUI s využitím vlastního jazyka nazvaného Kv. Jedná se ovšem o volitelnou variantu, protože v případě potřeby lze celé GUI naprogramovat i v čistém Pythonu – takže záleží jen na vývojáři, kterou variantu si vybere resp. která varianta je vhodnější pro konkrétní aplikaci.
Obrázek 4: Kivy se soustředí spíše na tvorbu GUI pro mobilní telefony a tablety s multitouch ovládáním. Nicméně lze použít i pro tvorbu desktopových aplikací.
Naprogramování aplikace s GUI vyžaduje provedení hned několika operací:
- Konstrukci resp. specifikaci ovládacích prvků (widgetů)
- Umístění těchto widgetů na plochu okna nebo dialogu
- Specifikaci, jakým způsobem bude aplikace reagovat na akce prováděné uživatelem (reakce na události)
- Programovou změnu vlastností zobrazených widgetů na základě operací prováděných aplikací (například změna zobrazené informace)
V dnešním článku se zaměříme na popis základních widgetů, které jsou knihovnou Kivy nabízeny. Ovšem zmíníme se i o tom, jakým způsobem se naprogramuje reakce na událost, která na GUI vznikne. Příkladem může být stisk tlačítka nebo změna pozice posuvníku.
Programátoři, co nesnášíte BS, ale máte rádi business! Y Soft je česká firma s globálním dopadem (100+ zemí, 1M+ uživatelů a >100% meziroční růst). R&D úplně bez manažerů (130 developerů). Otevíráme 30 pozic pro Cloud a AI: Praha/Brno/Ostrava/remote. Zodpovědnost ano, mikro-management ne. Pojď někam, kde můžeš věci změnit.
2. Jednodušší implementace aplikace s jediným oknem obsahujícím ovládací prvky
Připomeňme si jeden demonstrační příklad, který jsme si ukázali v předchozím článku a který dnes budeme rozšiřovat takovým způsobem, abychom si ukázali různé widgety nabízené knihovnou Kivy. V tomto příkladu je vytvořen dialog sloužící pro přihlášení k nějaké aplikaci. Implementace je založena na deklaraci třídy nazvané LoginScreen, která je odvozena od třídy GridLayout (což je jeden z kontejnerů pro widgety). V konstruktoru této třídy se nastavují základní vlastnosti kontejneru (šířka okrajů buněk atd.) a současně se zde vytváří i všechny widgety, které se mají zobrazit. Samotná aplikace je představována třídou nazvanou Application odvozenou od třídy App:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
class LoginScreen(GridLayout):
def __init__(self, **var_args):
super(LoginScreen, self).__init__(**var_args)
self.cols = 2
self.padding = 10
self.spacing = 10
# prvni radek mrizky
self.add_widget(Label(text="Name"))
self.username = TextInput(multiline=False)
self.add_widget(self.username)
# druhy radek mrizky
self.add_widget(Label(text="Password"))
self.password1 = TextInput(password=True, multiline=False)
self.add_widget(self.password1)
# treti radek mrizky
self.add_widget(Label(text="Confirm password"))
self.password2 = TextInput(password=True, multiline=False)
self.add_widget(self.password2)
# ctvrty radek mrizky
self.button = Button(text="Login")
self.add_widget(self.button)
class Application(App):
def build(self):
return LoginScreen()
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
Výsledná aplikace má GUI, které může vypadat takto:
Demonstrační příklady uvedené v navazujících kapitolách však vypadají poněkud odlišně. Namísto definice nové třídy odvozené od nějakého kontejneru je veškeré GUI aplikace deklarováno přímo v metodě Application.build. Právě v této metodě je zkonstruována instance třídy GridLayout a jsou do ní vloženy jednotlivé widgety. Instance této třídy je současně návratovou hodnotou metody build. Zdrojový kód takového příkladu je kratší a možná i lépe čitelný:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=2, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="Name")
layout.add_widget(label1)
username = TextInput(multiline=False)
layout.add_widget(username)
# druhy radek mrizky
label2 = Label(text="Password")
layout.add_widget(label2)
password1 = TextInput(password=True, multiline=False)
layout.add_widget(password1)
# treti radek mrizky
label3 = Label(text="Confirm password")
layout.add_widget(label3)
password2 = TextInput(password=True, multiline=False)
layout.add_widget(password2)
# ctvrty radek mrizky
button = Button(text="Login")
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
Po spuštění tohoto skriptu dostaneme prakticky stejné okno, jako v případě originálního skriptu:
3. Reakce na události
Při programování grafických uživatelských rozhraní je často používán pojem události (event(s)). Událostmi řízené programování je ostatně s programováním GUI prakticky neoddělitelně spojeno. Prakticky každý widget může v průběhu svého života generovat nějaké události. Naprostá většina událostí vzniká tak, že uživatel s widgetem interaktivně pracuje (například stlačí tlačítko zobrazené na obrazovce, vybere položku z menu, najede na ikonu apod.).
Ke každému widgetu je přitom ve většině knihoven a frameworků pro tvorbu GUI příslušná jedna „implicitní“ událost, na kterou reaguje. Tato událost se nastavuje pomocí změny vlastnosti widgetu (modifikace atributu), což bude ukázáno v demonstračních příkladech v následujících kapitolách. Kromě implicitní události lze na widgety navázat i další události, například tlačítko (button) může reagovat i na stlačení klávesy na klávesnici, na pravé tlačítko myši či na rolování kolečkem myši. Toto navázání se provádí nastavením atributu nebo předefinováním příslušné metody.
Konkrétně pro tlačítko button mohou být definovány reakce na následující události:
| on_press |
| on_release |
| on_kv_post |
| on_motion |
| on_opacity |
| on_ref_press |
| on_touch_down |
| on_touch_move |
| on_touch_up |
Naproti tomu pro návěští label je (logicky) dostupných událostí méně:
| on_kv_post |
| on_motion |
| on_opacity |
| on_ref_press |
| on_touch_down |
| on_touch_move |
| on_touch_up |
Nejvíce událostí vzniká u složitějších ovládacích prvků, například u vstupního textového pole:
| on__hint_text |
| on_cursor |
| on_cursor_blink |
| on_double_tap |
| on_handle_image_left |
| on_handle_image_middle |
| on_handle_image_right |
| on_kv_post |
| on_motion |
| on_opacity |
| on_padding_x |
| on_padding_y |
| on_quad_touch |
| on_selection_text |
| on_size |
| on_text_validate |
| on_touch_down |
| on_touch_move |
| on_touch_up |
| on_triple_tap |
Musíme si však uvědomit, že některé události se na různých operačních systémech a desktopových prostředích mohou generovat různým způsobem – typicky se jedná o přesun fokusu a v knihovně Kivy taktéž o události, které mohou být prováděny na dotykových displejích (gesta pro změnu velikosti, rotaci apod.)
4. Ukázka naprogramování reakce na události: stisk nebo uvolnění tlačítka umístěného na dialogu
Před popisem dalších widgetů, které knihovna Kivy vývojářům nabízí, je ovšem nutné do demonstračního příkladu doplnit ještě jednu funkci. Budeme totiž chtít, aby se po stisku tlačítka Ok okno aplikace uzavřelo a aby samotná aplikace byla ukončena. Ve skutečnosti to je velmi jednoduše splnitelná podmínka, protože tlačítka dokážou reagovat na událost (event), která vznikne při jejich stisku či uvolnění. Naprogramování operace vyvolané po stisku tlačítka může v tom nejjednodušším případě vypadat následovně:
button = Button(text="Ok") button.on_press=self.stop
V tomto konkrétním případě voláme callback metodu nazvanou App.stop, která skutečně celou aplikaci ukončí.
Úplný zdrojový kód takto upraveného demonstračního příkladu vypadá následovně:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="Basic widgets")
layout.add_widget(label1)
# druhy radek mrizky
label2 = Label()
layout.add_widget(label2)
# treti radek mrizky
button = Button(text="Ok")
button.on_press=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
Na tomto místě je ovšem dobré si uvědomit, že v případě tlačítek většina aplikací nereaguje na jejich stisk, ale naopak až na uvolnění, což mj. umožňuje nějakou operaci „odvolat“ tak, že se kurzor myši posune mimo tlačítko (což ovšem nemusí být plně funkční při ovládání přes dotykový displej). Zajištění, aby tlačítko reagovalo na své uvolnění a nikoli ihned na stisk, je velmi snadné, protože pouze postačuje změnit název atributu s referencí na callback metodu:
button = Button(text="Ok") button.on_release=self.stop
Pro úplnost si uvedeme celý zdrojový kód takto upraveného demonstračního příkladu:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="Basic widgets")
layout.add_widget(label1)
# druhy radek mrizky
label2 = Label()
layout.add_widget(label2)
# treti radek mrizky
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
5. Základní ovládací prvky (widgety) dostupné v knihovně Kivy
V průběhu několika desítek let postupného vývoje grafického uživatelského rozhraní se množina widgetů používaných v různých grafických uživatelských rozhraních postupně rozšiřovala. Ostatně postačí se podívat na obrázky z prvních grafických rozhraní navržených ve společnosti Xerox a porovnat je s moderním desktopem. Současně však také docházelo ke sjednocování vzhledu jednotlivých widgetů i jejich chování na různých platformách. Vzhled samozřejmě není na všech platformách přesně stejný, to však pro uživatele většinou nemusí představovat významnější praktický problém, na rozdíl od odlišného chování celého prostředí i jednotlivých widgetů.
V knihovně Kivy je k dispozici poměrně velké množství widgetů, podobně jako v dalších moderních toolkitech. V následující tabulce je uveden seznam základních typů widgetů. Pro mnoho aplikací je níže uvedená skupina widgetů dostačující, avšak v případě, že aplikace potřebuje vytvořit nový widget, je to samozřejmě možné, protože knihovna Kivy je navržena tak, že ji lze poměrně jednoduchým způsobem rozšiřovat (u nových widgetů je nutné naprogramovat jak jejich vzhled, tak i jejich chování). V následující tabulce si také můžete všimnout toho, že některé widgety jsou pojmenovány poněkud svérázným způsobem (Carousel atd.):
| Jméno widgetu |
|---|
| Label |
| TextInput |
| DropDown |
| ScrollView |
| Carousel |
| Slider |
| Image |
| Switch |
| Spinner |
| Splitter |
| ProgressBar |
| Bubble |
| TabbedPanel |
| Scatter |
| Accordion |
| ToggleButton |
| TreeView |
| ActionBar |
6. Tlačítko se dvěma stavy – ToggleButton
Prozatím jsme si vyzkoušeli použití tří základních widgetů. Konkrétně se jednalo o návěští (Label), vstupní textové pole (TextInput) a taktéž o běžné tlačítko (Button). Dalším widgetem, který je možné použít, je tlačítko, které má dva stavy – stisknuto a uvolněno. Jedná se tedy o kombinaci běžného tlačítka s výběrovým boxem, který má taktéž dva stavy. Stav tlačítka je reprezentován změnou jeho barvy a popř. i tvaru (v závislosti na nastavených stylech). Tím, že pro zobrazení stavu není nutné vykreslit například symbol ✔, může být použití tlačítka se dvěma stavy výhodnější, než výběrový box, a to v případě, že jsme omezeni plochou pro zobrazení dialogu. A navíc je možné tato tlačítka sdružit do skupin; přičemž v každé skupině může být vybráno jediné tlačítko:
class ToggleButton(kivy.uix.behaviors.togglebutton.ToggleButtonBehavior, kivy.uix.button.Button) | ToggleButton(**kwargs) | | Toggle button class, see module documentation for more information. | | Method resolution order: | ToggleButton | kivy.uix.behaviors.togglebutton.ToggleButtonBehavior | kivy.uix.button.Button | kivy.uix.behaviors.button.ButtonBehavior | kivy.uix.label.Label | kivy.uix.widget.Widget | kivy.uix.widget.WidgetBase | kivy._event.EventDispatcher | kivy._event.ObjectWithUid | builtins.object ... ......
Události, na které může tento typ tlačítka reagovat, se do značné míry podobají událostem běžných tlačítek (až na on_group):
| on_group |
| on_kv_post |
| on_motion |
| on_opacity |
| on_press |
| on_ref_press |
| on_release |
| on_touch_down |
| on_touch_move |
| on_touch_up |
7. Demonstrační příklad: dialog s tlačítkem se dvěma stavy
Vytvoření okna resp. dialogu, který obsahuje tlačítko se dvěma stavy, je snadné. Nejprve musíme naimportovat třídu nazvanou ToggleButton z knihovny Kivy:
from kivy.uix.togglebutton import ToggleButton
Konstrukce tlačítka se dvěma stavy s jeho umístěním do dialogu:
toggle_button = ToggleButton(text="Toggle") layout.add_widget(toggle_button)
Dále je možné určit výchozí stav tlačítka:
toggle_button = ToggleButton(text="Toggle", state="Down") layout.add_widget(toggle_button)
Popř. můžeme určit skupinu, do které takové tlačítko patří:
toggle_button = ToggleButton(text="Toggle", state="Down", group="colors") layout.add_widget(toggle_button)
Ukažme si základní způsob použití přepínacího tlačítka, které do našeho demonstračního příkladu přidáme:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="ToggleButton")
layout.add_widget(label1)
# druhy radek mrizky
toggle_button = ToggleButton(text="Toggle")
layout.add_widget(toggle_button)
# treti radek mrizky
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
Chování takového tlačítka snadno ověříme po spuštění skriptu:
8. Zaškrtávací pole – Checkbox
Dalším typem grafického ovládacího prvku (widgetu) je takzvané zaškrtávací pole, dnes poněkud nepřesně nazývané Checkbox. Od obyčejného tlačítka nebo tlačítka se dvěma stavy se tento widget liší především tím, že je vizuálně patrný jeho stav – nastaveno/nenastaveno. Tento typ ovládacích prvků je zobrazován různým způsobem, typicky se však jedná o čtvereček, který je buď zatržený (znak ✓ či ×) nebo prázdný; v některých GUI prostředích se však stav tlačítka reprezentuje pouze jeho barvou. V knihovně Kivy je tento ovládací prvek reprezentován třídou CheckBox (povšimněte si, že dědí vlastnosti přepínacího tlačítka):
class CheckBox(kivy.uix.behaviors.togglebutton.ToggleButtonBehavior, kivy.uix.widget.Widget) | CheckBox(**kwargs) | | CheckBox class, see module documentation for more information. | | Method resolution order: | CheckBox | kivy.uix.behaviors.togglebutton.ToggleButtonBehavior | kivy.uix.behaviors.button.ButtonBehavior | kivy.uix.widget.Widget | kivy.uix.widget.WidgetBase | kivy._event.EventDispatcher | kivy._event.ObjectWithUid | builtins.object ... ... ...
Důležitý je atribut active, kterým se řídí, zda je zaškrtávací pole vybráno či nikoli.
Opět si vypišme všechny události, na které dokáže tento ovládací prvek reagovat:
| on_group |
| on_kv_post |
| on_motion |
| on_opacity |
| on_press |
| on_release |
| on_touch_down |
| on_touch_move |
| on_touch_up |
9. Demonstrační příklad: dialog se zaškrtávacím polem
Umístění zaškrtávacího pole do plochy okna nebo dialogu je snadné, ovšem samotný popis je nutné umístit do jiného typu widgetu, typicky do návěští. Pokud použijeme správce rozvržení GridLayout, může být umístění popisku+samotného zaškrtávacího pole realizováno následovně:
label1 = Label(text="I really want to receive spam") layout.add_widget(label1) check_box = CheckBox(active=True) layout.add_widget(check_box)
Celý zdrojový kód takto upraveného dialogu může vypadat takto:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="I really want to receive spam")
layout.add_widget(label1)
# druhy radek mrizky
check_box = CheckBox(active=True)
layout.add_widget(check_box)
# treti radek mrizky
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
Výsledné okno zobrazené na ploše desktopu:
10. Několik na sobě nezávislých zaškrtávacích polí
Samozřejmě nám nic nebrání v tom, aby bylo na plochu okna nebo dialogu umístěno hned několik zaškrtávacích polí. V dalším demonstračním příkladu je vždy v levém sloupci zobrazen popisek a v pravém sloupci je příslušné zaškrtávací pole:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=2, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="I really want to receive spam")
layout.add_widget(label1)
ack1 = CheckBox(active=True)
layout.add_widget(ack1)
# druhy radek mrizky
label2 = Label(text="Share my data with FAANG")
layout.add_widget(label2)
ack2 = CheckBox(active=True)
layout.add_widget(ack2)
# treti radek mrizky
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (420, 160)
if __name__ == "__main__":
Application().run()
Takto vypadá výsledný dialog:
V navazujícím článku si popíšeme i způsob zmenšení šířky jednotlivých sloupců, proto si dnes jen v rychlosti ukážeme, jak lze dialog nepatrně vylepšit (viz zvýrazněné části kódu):
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=2, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="I really want to receive spam")
layout.add_widget(label1)
ack1 = CheckBox(active=True, size_hint_x=None, width=50)
layout.add_widget(ack1)
# druhy radek mrizky
label2 = Label(text="Share my data with FAANG")
layout.add_widget(label2)
ack2 = CheckBox(active=True, size_hint_x=None, width=50)
layout.add_widget(ack2)
# treti radek mrizky
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (350, 160)
if __name__ == "__main__":
Application().run()
Výsledný dialog bude vypadat následovně:
11. Přepínač – RadioButton
Dalším velmi často používaným ovládacím prvkem (přesněji řečeno specializovanou variantou tlačítka) je takzvaný RadioButton (přepínač). Tento typ widgetu se od předchozích dvou typů widgetů (tedy od ToggleButton a Checkbutton) odlišuje především tím, že je používán ve větších skupinách. Z každé skupiny přitom může být vybrán (nastaven) pouze jeden přepínač, od čehož je ostatně odvozen původní anglický název tohoto ovládacího prvku, protože připomíná přepínač kanálů na starších rádiích (ale používal se i na některých televizorech, ovšem hodně dávno).
V mnoha knihovnách pro tvorbu grafického uživatelského rozhraní jsou přepínače realizovány jako samostatný typ widgetu, ovšem v knihovně Kivy tomu tak není, protože radiová tlačítka vzniknou takovým způsobem, že se sdruží několik zatrhávacích boxů do jedné skupiny. Kivy v takovém případě namísto zatrhávacích boxů automaticky vykreslí přepínací tlačítka. Jak se však pozná, které přepínače patří k sobě, tj. do jedné skupiny? Skupina je určena při konstrukci widgetů: jedná se typicky o řetězec, který musí být pro přepínače v jedné skupině totožný. Tento řetězec se předává při konstrukci tlačítka v nepovinném parametru group:
color = CheckBox(group="colors")
12. Demonstrační příklad: zaškrtávací pole, které nepatří do jedné skupiny
V dalším demonstračním příkladu je vytvořen dialog, ve kterém se nachází zaškrtávací pole, která umožní výběr barev z nabízeného spektra osmi barev. Kvůli tomu, že zaškrtávací pole nepatří do žádné skupiny, bude každý z těchto widgetů skutečně zobrazen jako samostatné zaškrtávací pole a bude tedy možné vybrat jakoukoli kombinaci barev (nebo žádnou barvu):
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=2, padding=10, spacing=10)
colors = ("Black", "Red", "Green", "Blue", "Cyan", "Magenta", "Yellow", "White")
for color in colors:
label = Label(text=color)
layout.add_widget(label)
color = CheckBox()
layout.add_widget(color)
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (300, 360)
if __name__ == "__main__":
Application().run()
A takto bude vypadat výsledný dialog zobrazený na ploše desktopu:
13. Demonstrační příklad: přepínače vytvořené ze zaškrtávacích polí
Nepatrnou změnou provedenou ve zdrojovém kódu demonstračního příkladu lze dosáhnout toho, že se namísto na sobě nezávislých zaškrtávacích polí zobrazí sada na sobě závislých přepínačů (vybrán může být jen jeden z nich):
color = CheckBox(group="colors")
Výsledný dialog bude zcela odlišný od dialogu předchozího, a to jak vzhledem, tak i chováním:
Pro úplnost je uveden celý zdrojový kód tohoto příkladu:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=2, padding=10, spacing=10)
colors = ("Black", "Red", "Green", "Blue", "Cyan", "Magenta", "Yellow", "White")
for color in colors:
label = Label(text=color)
layout.add_widget(label)
color = CheckBox(group="colors")
layout.add_widget(color)
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (300, 360)
if __name__ == "__main__":
Application().run()
14. Posuvník (Slider)
Dalším ovládacím prvkem grafického uživatelského rozhraní, který si v dnešním článku popíšeme, je posuvník. Většinou se tento ovládací prvek nazývá slider (což je i případ knihovny Kivy), ovšem například v knihovně appJar zvolili název scale. Posuvník se v nejjednodušším případě vytváří vytvořením instance třídy Slider:
class Slider(kivy.uix.widget.Widget) | Slider(**kwargs) | | Class for creating a Slider widget. | | Check module documentation for more details. | | Method resolution order: | Slider | kivy.uix.widget.Widget | kivy.uix.widget.WidgetBase | kivy._event.EventDispatcher | kivy._event.ObjectWithUid | builtins.object
Při konstrukci posuvníku se typicky nastavují tři vlastnosti: minimální hodnota odpovídající situaci, kdy je posuvník umístěn na levém okraji, maximální hodnota (pravý okraj) a výchozí hodnota:
slider = Slider(min=0, max=100, value=25)
Navíc je možné specifikovat, že se má posuvník zobrazit s vertikální orientací:
slider = Slider(min=0, max=100, value=25, orientation="Vertical")
Události, na které může posuvník reagovat, jsou do značné míry odlišné od událostí, na které reagovaly předchozí typy widgetů:
| on_kv_post |
| on_max |
| on_min |
| on_motion |
| on_opacity |
| on_touch_down |
| on_touch_move |
| on_touch_up |
15. Demonstrační příklad: posuvníky v dialogovém okně
V dalším demonstračním příkladu je do dialogového okna vložena trojice posuvníků, jejichž hodnoty jsou v rozmezí 0 až 100 a každý z těchto posuvníků má nastavenou odlišnou počáteční pozici. Všechny posuvníky mají výchozí (horizontální) orientaci:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.slider import Slider
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10)
slider = Slider(min=0, max=100, value=25)
layout.add_widget(slider)
slider = Slider(min=0, max=100, value=50)
layout.add_widget(slider)
slider = Slider(min=0, max=100, value=75)
layout.add_widget(slider)
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 260)
if __name__ == "__main__":
Application().run()
Výsledný vzhled dialogu se skupinou posuvníků:
16. Nastavení barvy ovládacích prvků
V knihovně Kivy má většina základních ovládacích prvků „plochý“ vzhled, což mj. znamená, že se mnohdy jedná o prakticky jednobarevné plochy, popř. plochy s okraji. Barvy jednotlivých částí ovládacích prvků je přitom možné modifikovat, a to jak přímo ve skriptu napsaném v Pythonu, tak i v popisu GUI založeného na jazyku Kv. Příkladem může být běžné tlačítko nebo tlačítko se dvěma stavu, u kterého lze nastavit hned několik barev (pro různé stavy a různé části tlačítka):
| color |
| background_color |
| outline_color |
| disabled_color |
| disabled_outline_color |
Samotná barva je reprezentována čtveřicí hodnot [červená, zelená, modrá, intenzita/neprůhlednost]. Změna pozadí (plochy) ovládacích prvků je tedy snadná:
toggle_button = ToggleButton(text="Toggle") toggle_button.background_color=[1.0, 0.4, 0.6, 1]
popř. pro běžné tlačítko:
button = Button(text="Ok") button.background_color=[0.4, 1.0, 0.4, 1]
Výsledky na ploše desktopu budou vypadat takto:
Opět si pochopitelně ukážeme i celý zdrojový kód demonstračního příkladu, který vykreslil GUI ze screenshotů číslo 12 a 13:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="Background color")
layout.add_widget(label1)
# druhy radek mrizky
toggle_button = ToggleButton(text="Toggle")
toggle_button.background_color=[1.0, 0.4, 0.6, 1]
layout.add_widget(toggle_button)
# treti radek mrizky
button = Button(text="Ok")
button.background_color=[0.4, 1.0, 0.4, 1]
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
17. Vytvoření ikony z běžného tlačítka
Knihovna Kivy sice přímo neobsahuje widget typu „ikona“, ovšem v případě potřeby si můžeme (klikací) ikonu relativně snadno zkonstruovat například z běžného tlačítka nebo z tlačítka přepínacího – potom bude mít dva stavy. Postačuje nastavit vlastnost s cestou k obrázku background_normal a vhodným způsobem upravit rozměry tlačítka:
icon = Button(text="", size=(45, 40), size_hint_x=None) icon.background_normal="button-open.png"
Výsledný dialog bude vypadat následovně:
Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10)
# prvni radek mrizky
label1 = Label(text="Icon button")
layout.add_widget(label1)
# druhy radek mrizky
icon = Button(text="", size=(45, 40), size_hint_x=None)
icon.background_normal="button-open.png"
layout.add_widget(icon)
# treti radek mrizky
button = Button(text="Ok")
button.background_color=[0.4, 1.0, 0.4, 1]
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 180)
if __name__ == "__main__":
Application().run()
18. Interaktivní nastavení barvy ovládacího prvku pomocí posuvníků
V poslední dvojici demonstračních příkladů je ukázáno, jakým způsobem se mohou použít posuvníky pro interaktivní změnu barvy textu (textového návěští). U každého posuvníku je specifikována callback metoda, která modifikuje jeden z atributů objektu typu Application:
slider_red = Slider(min=0, max=100, value=25)
slider_red.fbind("value", self.on_red_slider_change)
Příslušné metodě je předána instance (reference na instanci) posuvníku a taktéž jeho aktuální hodnota v rozsahu 0..100. Z této hodnoty snadno vypočítáme barvovou složku:
def on_red_slider_change(self, instance, value):
self.red = value / 100.0
self.change_color()
Samotná metoda pro změnu barvy textového návěští vypadá takto:
def change_color(self):
self.label_rgb.color = (self.red, self.green, self.blue, 1.0)
Výsledkem je interaktivní dialog:
Úplný zdrojový kód tohoto demonstračního příkladu:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.slider import Slider
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=2, padding=10, spacing=10)
label = Label(text="Red")
layout.add_widget(label)
slider_red = Slider(min=0, max=100, value=25)
slider_red.fbind("value", self.on_red_slider_change)
layout.add_widget(slider_red)
label = Label(text="Green")
layout.add_widget(label)
slider_green = Slider(min=0, max=100, value=50)
slider_green.fbind("value", self.on_green_slider_change)
layout.add_widget(slider_green)
label = Label(text="Blue")
layout.add_widget(label)
slider_blue = Slider(min=0, max=100, value=75)
slider_blue.fbind("value", self.on_blue_slider_change)
layout.add_widget(slider_blue)
self.label_rgb = Label(text="[size=40pt][b]Test[/b][/size]", markup=True)
layout.add_widget(self.label_rgb)
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_red_slider_change(self, instance, value):
self.red = value / 100.0
self.change_color()
def on_green_slider_change(self, instance, value):
self.green = value / 100.0
self.change_color()
def on_blue_slider_change(self, instance, value):
self.blue = value / 100.0
self.change_color()
def change_color(self):
self.label_rgb.color = (self.red, self.green, self.blue, 1.0)
def on_start(self):
self.red = 0.25
self.green = 0.50
self.blue = 0.75
Window.size = (420, 240)
self.change_color()
if __name__ == "__main__":
Application().run()
Pro zajímavost si ještě ukažme, jak by vypadal alternativní dialog, ve kterém budou posuvníky vertikální. Tomu se budou muset přizpůsobit i další ovládací prvky umístěné na dialogu. Lepšího výsledku bychom dosáhli použitím odlišného správce rozvržení komponent, což je však téma, kterým se budeme zabývat příště:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.slider import Slider
from kivy.uix.label import Label
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = GridLayout(cols=5, padding=10, spacing=10)
slider_red = Slider(min=0, max=100, value=25, orientation="vertical")
slider_red.fbind("value", self.on_red_slider_change)
layout.add_widget(slider_red)
slider_green = Slider(min=0, max=100, value=50, orientation="vertical")
slider_green.fbind("value", self.on_green_slider_change)
layout.add_widget(slider_green)
slider_blue = Slider(min=0, max=100, value=75, orientation="vertical")
slider_blue.fbind("value", self.on_blue_slider_change)
layout.add_widget(slider_blue)
self.label_rgb = Label(text="[size=40pt][b]T\ne\ns\nt[/b][/size]", markup=True)
layout.add_widget(self.label_rgb)
button = Button(text="Ok")
button.on_release=self.stop
layout.add_widget(button)
return layout
def on_red_slider_change(self, instance, value):
self.red = value / 100.0
self.change_color()
def on_green_slider_change(self, instance, value):
self.green = value / 100.0
self.change_color()
def on_blue_slider_change(self, instance, value):
self.blue = value / 100.0
self.change_color()
def change_color(self):
self.label_rgb.color = (self.red, self.green, self.blue, 1.0)
def on_start(self):
self.red = 0.25
self.green = 0.50
self.blue = 0.75
Window.size = (300, 400)
self.change_color()
if __name__ == "__main__":
Application().run()
Nyní bude dialog po zobrazení na ploše desktopu vypadat takto:
19. Repositář s demonstračními příklady
Demonstrační příklady, s nimiž jsme se minule i dnes seznámili a které jsou určeny pro Python 3.11 (a libovolnou vyšší verzi Pythonu) a knihovnu Kivy, jsou dostupné, jak je zvykem, na GitHubu. V tabulce níže jsou uvedeny odkazy na jednotlivé zdrojové kódy i na definice formulářů:
20. Odkazy na Internetu
- Welcome to KivyMD’s documentation!
https://kivymd.readthedocs.io/en/latest/ - Kivy Tutorial
https://www.geeksforgeeks.org/python/kivy-tutorial/ - Stránky projektu Kivy
https://kivy.org/#home - Two Ways To Change Background Colors – Python Kivy GUI Tutorial
https://kivycoder.com/two-ways-to-change-background-colors-python-kivy-gui-tutorial-11/ - 5 Best Ways to Adjust Window Size in Kivy with Python
https://blog.finxter.com/5-best-ways-to-adjust-window-size-in-kivy-with-python/ - Python | Make a simple window using kivy
https://www.geeksforgeeks.org/python/python-make-a-simple-window-using-kivy/ - Python | Ellipse (different polygons) in Kivy
https://www.geeksforgeeks.org/python/python-ellipse-different-polygons-in-kivy/ - Getting Started » Kv Design Language
https://kivy.org/doc/stable/gettingstarted/rules.html - Python | Kivy .kv File
https://www.geeksforgeeks.org/python/python-kivy-kv-file/ - Kivy na GitHubu
https://github.com/kivy/kivy - PySimpleGUI
https://www.pysimplegui.org/en/latest/ - DearPyGui na GitHubu
https://github.com/hoffstadt/DearPyGui - PySimpleGUI Tutorial
https://www.tutorialspoint.com/pysimplegui/index.htm - PySimpleGUI – Canvas Element
https://www.tutorialspoint.com/pysimplegui/pysimplegui_canvas_element.htm - Dokumentace ke knihovně PySimpleGUI
https://www.pysimplegui.org/en/latest/ - Dokumentace ke knihovně DearPyGui
https://dearpygui.readthedocs.io/en/latest/index.html# - The Hitchhiker's Guide to Pyhton: GUI Applications
http://docs.python-guide.org/en/latest/scenarios/gui/ - 7 Top Python GUI Frameworks for 2017
http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/ - Stránky projektu wxPython
https://wxpython.org/ - wxPython Project Phoenix (na GitHubu)
https://github.com/wxWidgets/Phoenix/blob/wxPython-4.0.3/README.rst - wxPython API Documentation
https://docs.wxpython.org/index.html - wxWidgets
https://wxwidgets.org/ - wxPython 4.0.3 na PyPi
https://pypi.org/project/wxPython/4.0.3/ - wxGlade – a GUI builder for wxWidgets
http://wxglade.sourceforge.net/ - Repositář projektu wxGlade
https://github.com/wxGlade/wxGlade/ - wxGlade’s documentation
http://wxglade.sourceforge.net/docs/index.html - Graphical User Interfaces (GUI)
https://pythonspot.com/gui/ - wxPyWiki
https://wiki.wxpython.org/FrontPage - Getting started with wxPython
https://wiki.wxpython.org/Getting%20Started#A_First_Application:_.22Hello.2C_World.22 - wxPython GUI tutorial
https://pythonspot.com/wxpython-gui-tutorial/ - wxPython tutorial
http://zetcode.com/wxpython/ - Build wxPython On Raspberry Pi
https://wiki.wxpython.org/BuildWxPythonOnRaspberryPi - wxPython History
https://wxpython.org/pages/history/index.html - Installing wxPython 4.0 (Project Phoenix) on Fedora 27
https://blog.wizardsoftheweb.pro/installing-wxpython-on-fedora/ - Category:Software that uses wxWidgets
https://en.wikipedia.org/wiki/Category:Software_that_uses_wxWidgets - Hra Breakout napísaná v Tkinteri
https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/ - GUI Programming in Python
https://wiki.python.org/moin/GuiProgramming - Cameron Laird's personal notes on Python GUIs
http://phaseit.net/claird/comp.lang.python/python_GUI.html - Python GUI development
http://pythoncentral.io/introduction-python-gui-development/ - Hand Coded GUI Versus Qt Designer GUI
https://stackoverflow.com/questions/387092/hand-coded-gui-versus-qt-designer-gui - Qt Creator Manual
http://doc.qt.io/qtcreator/ - Qt Designer Manual
http://doc.qt.io/qt-5/qtdesigner-manual.html - Qt Creator (Wikipedia)
https://en.wikipedia.org/wiki/Qt_Creator - QIODevice
https://pyside.github.io/docs/pyside/PySide/QtCore/QIODevice.html#PySide.QtCore.QIODevice - QFile
https://pyside.github.io/docs/pyside/PySide/QtCore/QFile.html#PySide.QtCore.QFile - QUiLoader
https://pyside.github.io/docs/pyside/PySide/QtUiTools/QUiLoader.html#PySide.QtUiTools.PySide.QtUiTools.QUiLoader.load - QSvgWidget
https://pyside.github.io/docs/pyside/PySide/QtSvg/QSvgWidget.html - QByteArray
https://pyside.github.io/docs/pyside/PySide/QtCore/QByteArray.html - Differences Between PySide and PyQt
https://wiki.qt.io/Differences_Between_PySide_and_PyQt - PySide 1.2.1 tutorials
https://pyside.github.io/docs/pyside/tutorials/index.html - PySide tutorial
http://zetcode.com/gui/pysidetutorial/ - Drawing in PySide
http://zetcode.com/gui/pysidetutorial/drawing/ - Qt Core
https://pyside.github.io/docs/pyside/PySide/QtCore/Qt.html - Signals & Slots
http://doc.qt.io/qt-4.8/signalsandslots.html - Signals and Slots in PySide
http://wiki.qt.io/Signals_and_Slots_in_PySide - Intro to PySide/PyQt: Basic Widgets and Hello, World!
http://www.pythoncentral.io/intro-to-pysidepyqt-basic-widgets-and-hello-world/ - Leo editor
http://leoeditor.com/ - IPython Qt Console aneb vylepšený pseudoterminál
https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-ipython-a-ipython-notebook/#k06 - Python GUI development
http://pythoncentral.io/introduction-python-gui-development/ - Graphic User Interface FAQ
https://docs.python.org/2/faq/gui.html#graphic-user-interface-faq - Tkinter
https://wiki.python.org/moin/Tkinter - Tkinter 8.5 reference: a GUI for Python
http://infohost.nmt.edu/tcc/help/pubs/Tkinter/web/index.html - Tkinter (Wikipedia)
https://en.wikipedia.org/wiki/Tkinter - appJar
http://appjar.info/ - appJar (Wikipedia)
https://en.wikipedia.org/wiki/AppJar - appJar na Pythonhosted
http://pythonhosted.org/appJar/ - appJar widgets
http://appjar.info/pythonWidgets/ - Stránky projektu PyGTK
http://www.pygtk.org/ - PyGTK (Wikipedia)
https://cs.wikipedia.org/wiki/PyGTK - Stránky projektu PyGObject
https://wiki.gnome.org/Projects/PyGObject - Stránky projektu PyQt
https://riverbankcomputing.com/software/pyqt/intro - What's on the Kivy Roadmap?
https://github.com/orgs/kivy/discussions/10 - Graphical user interface (Wikipedia)
http://en.wikipedia.org/wiki/Graphical_user_interface - The Real History of the GUI
http://articles.sitepoint.com/article/real-history-gui - History of the graphical user interface (Wikipedia)
http://en.wikipedia.org/wiki/History_of_the_graphical_user_interface - Creating a GUI with Python: A Comprehensive Guide
https://coderivers.org/blog/how-to-create-a-gui-with-python/ - NiceGUI
https://nicegui.io/ - Buildozer’s documentation
https://buildozer.readthedocs.io/en/latest/ - buildozer 1.5.0 na PyPi
https://pypi.org/project/buildozer/ - Kivy 2.3.1 na PyPi
https://pypi.org/project/Kivy/ - pyglet 2.1.11 na PyPi
https://pypi.org/project/pyglet/ - pyglet Documentation
https://pyglet.readthedocs.io/en/latest/
















