Obsah
3. Základní způsob použití kontejneru anchor layout
4. Další příklady použití kontejneru anchor layout
5. Specifikace kontejneru anchor layout v jazyce Kv
6. Kontejner typu float layout
7. Vložení komponent do kontejneru float layout bez specifikace jejich pozice
8. Vložení komponent do kontejneru float layout se specifikací jejich pozice
9. Programový výpočet pozice komponent
10. Kontejner typu relative layout
11. Příklad použití kontejneru relative layout
12. Kontejner typu page layout
13. Příklady použití kontejneru page layout
14. Složitější příklad s dvojicí dialogů, mezi nimiž je možné se přepínat
16. Vykreslení čtverce na plochu kreslicího plátna
17. Využití správce kontextu (context manager)
18. Obsah následující části seriálu
19. Repositář s demonstračními příklady
1. Tvorba grafického uživatelského rozhraní v Pythonu s využitím knihovny Kivy: kontejnery a kreslicí plátno
V předchozím článku o knihovně Kivy jsme se zabývali popisem takzvaných kontejnerů. Kivy totiž, ostatně podobně jako většina dalších moderních nástrojů pro tvorbu grafického uživatelského rozhraní, na plochu okna/dialogu neumisťuje přímo ovládací prvky (widgety), ale ponechává tuto činnost právě na kontejnerech, které jsou někdy nazývány i správci geometrie. Kontejnery se starají jak o přesné umístění komponenty (například tlačítka) na plochu okna, tak i o nastavení jejich velikosti. To mj. umožňuje tvorbu aplikací, které jsou do značné míry nezávislé na rozlišení monitoru a v případě Kivy může taková aplikace běžet jak na běžném desktopu, tak i například na tabletu nebo na chytrém telefonu.
Prozatím jsme si popsali trojici kontejnerů. V první řadě se jednalo o kontejner pojmenovaný grid layout, který dokáže komponenty umístit do pomyslné mřížky. Výsledek může vypadat například takto:
Druhý kontejner, který byl taktéž popsán minule, je kontejner nazvaný stack layout. Jedná se o relativně jednoduše použitelný kontejner, který umisťuje komponenty za sebou nebo pod sebou s tím, že v případě potřeby mohou komponenty „přetéct“ na další pomyslné řádky (podobně jako znaky v textových editorech). Výsledné rozmístění komponent může vypadat například takto:
Obrázek 2: Automatické rozmístění tlačítek ve výchozím stavu, kdy je okno široké 200 délkových jednotek.
A konečně třetím popsaným kontejnerem byl box layout. Tento kontejner dokáže zajistit, že komponenty jsou umístěny buď vedle sebe nebo pod sebe, ovšem nedokážou automaticky „přetéct“ tak, jako v případě předchozího kontejneru. Výsledek může vypadat následovně:
V dnešním článku si popíšeme další čtyři typy kontejnerů. Jedná se o kontejnery pojmenované anchor layout, float layout, relative layout a konečně asi nejzvláštnější dostupný kontejner vůbec – page layout.
Druhá část článku bude věnována problematice kreslicího plátna (canvasu).
2. Kontejner anchor layout
Prvním kontejnerem, se kterým se v dnešním článku seznámíme, je kontejner nazývaný anchor layout. V určitých ohledech se jedná o dosti zvláštní typ kontejneru, protože je do něho možné vložit pouze jedinou komponentu, zatímco v případě ostatních typů kontejnerů ve možné pracovat s větším množstvím komponent. Tato jediná komponenta může být „ukotvena“ (odtud pochází název kontejneru) k některému okraji rezervované plochy. Ukotvení je možné specifikovat v horizontálním směru (k levému nebo pravému okraji) i ve směru vertikálním (k hornímu nebo spodnímu okraji). Pokud není ukotvení určeno, bude komponenta v daném směru vycentrována vzhledem k dostupné ploše (hodnota center je výchozí). To tedy znamená, že komponentu lze umístit (ukotvit) devíti možnými způsoby:
| # | anchor_x | anchor_y | umístění komponenty |
|---|---|---|---|
| 1 | center | center | uprostřed plochy |
| 2 | center | top | horní okraj |
| 3 | center | bottom | dolní okraj |
| 4 | left | center | levý okraj |
| 5 | left | top | levý horní roh |
| 6 | left | bottom | levý dolní roh |
| 7 | right | center | pravý okraj |
| 8 | right | top | pravý horní roh |
| 9 | right | bottom | pravý dolní roh |
3. Základní způsob použití kontejneru anchor layout
V dnešním prvním demonstračním příkladu je ukázáno, jakým způsobem se kontejner typu anchor layout používá. Vzhledem k tomu, že tento kontejner může obsahovat jen jediný ovládací prvek (widget), je demonstrační příklad velmi jednoduchý. Do okna o rozměrech 400×300 jednotek je vložen kontejner a do něho je přidáno tlačítko s nastavenými relativními rozměry. Tlačítko je umístěno doprostřed okna (resp. přesněji řečeno doprostřed plochy ovládané kontejnerem):
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího AnchorLayout
# - dialog obsahuje jediné tlačítko, které je vycentrované
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = AnchorLayout()
button = Button(text="Click!", size_hint=(0.5, 0.5))
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 300)
if __name__ == "__main__":
Application().run()
Výsledek by měl vypadat takto:
4. Další příklady použití kontejneru anchor layout
Ve druhé kapitole bylo popsáno všech devět možných způsobů ukotvení komponenty v ploše ovládané kontejnerem. Ukažme si tedy, jak bude vypadat návrh dialogu, ve kterém bude tlačítko horizontálně vycentrováno a vertikálně ukotveno k dolnímu okraji okna. Velikost tlačítka je nastavena na 1/2 výšky i šířky dostupné plochy:
layout = AnchorLayout(anchor_y="bottom") button = Button(text="Click!", size_hint=(0.5, 0.5)) layout.add_widget(button)
Výsledná vizuální podoba dialogového okna:
Obrázek 6: Tlačítko, které je vycentrováno v horizontálním směru a dotýká se dolního okraje plochy řízené kontejnerem typu anchor layout.
Následuje úplný výpis skriptu, který toto okno vykreslil:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího AnchorLayout
# - dialog obsahuje jediné tlačítko, které je horizontálně vycentrované
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = AnchorLayout(anchor_y="bottom")
button = Button(text="Click!", size_hint=(0.5, 0.5))
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 300)
if __name__ == "__main__":
Application().run()
Podobným způsobem můžeme tlačítko umístit do pravého spodního rohu okna:
layout = AnchorLayout(anchor_x="right", anchor_y="bottom") button = Button(text="Click!", size_hint=(0.5, 0.5)) layout.add_widget(button)
Výsledek:
Opět si ukážeme celý skript, který toto dialogové okno vytvořil:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího AnchorLayout
# - dialog obsahuje jediné tlačítko, které je umístěno v rohu
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = AnchorLayout(anchor_x="right", anchor_y="bottom")
button = Button(text="Click!", size_hint=(0.5, 0.5))
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 300)
if __name__ == "__main__":
Application().run()
5. Specifikace kontejneru anchor layout v jazyce Kv
Kontejner typu anchor layout je pochopitelně možné využít i v dialogu popsaném v jazyku Kv. Dialog podobný tomu z dnešního prvního demonstračního příkladu by mohl být definován i takto:
AnchorLayout:
id: anchor_layout
padding: 0
spacing: 0
anchor_x: 'center'
anchor_y: 'center'
Button:
text: "Click"
size_hint: [1/2, 1/2]
Načtení definice dialogu v jazyku Kv, inicializace aplikace a zobrazení okna s dialogem se realizuje následovně:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - načtení definice dialogu popsaného v jazyku Kv
# - dialog je postaven na kontejneru typu AnchorLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
class Application(App):
def build(self):
builder = Builder.load_file("anchor_layout.kv")
return builder
def on_start(self):
Window.size = (400, 300)
if __name__ == "__main__":
Application().run()
Výsledek:
6. Kontejner typu float layout
Všechny doposud popsané kontejnery měly (i přes mnohé rozdíly) jednu vlastnost společnou – o přesné umístění komponent se staral přímo kontejner, který na základě zadaných pravidel vypočítal jak jejich umístění, tak i velikost. To umožňuje tvorbu aplikací, které mohou být (při troše snahy) přenositelné jak na desktopy, tak i na tablety, smartphony, velké prezentační obrazovky atd. Ovšem za tuto univerzalitu platíme, protože naprosto přesné umístění komponent je v takových případech složité až nemožné. Pokud je nutné, aby aplikace měla absolutní kontrolu nad tím, na jakém místě a s jakou velikostí budou komponenty zobrazeny, lze použít kontejner typu float layout. Ten umožňuje přesné určení souřadnic komponenty v rámci lokálního souřadného systému. Počátek tohoto souřadného systému přitom leží v levém dolním rohu (pozor, nikoli v rohu horním).
7. Vložení komponent do kontejneru float layout bez specifikace jejich pozice
U většiny kontejnerů nabízených knihovnou Kivy postačuje nastavit jejich vlastnosti už při volání konstruktoru a poté je již možné do kontejneru vkládat jednotlivé komponenty, které jsou kontejnerem automaticky „přeskládány“. V případě kontejneru typu float layout je tomu ovšem jinak, což si ostatně ukážeme. V prvním příkladu do kontejneru vložíme devět tlačítek, aniž bychom explicitně specifikovali jejich pozici:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího FloatLayout
# - dialog obsahuje devět tlačítek se stejnými vlastnostmi
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = FloatLayout()
button = Button(text="1", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="2", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="3", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="4", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="5", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="6", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="7", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="8", size_hint=(1/4, 1/4))
layout.add_widget(button)
button = Button(text="9", size_hint=(1/4, 1/4))
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (200, 200)
if __name__ == "__main__":
Application().run()
Výsledkem bude, že všechna tlačítka budou umístěna na stejné souřadnice a vzhledem k tomu, že jejich velikosti jsou shodné, bude viditelné pouze poslední (deváté) tlačítko:
8. Vložení komponent do kontejneru float layout se specifikací jejich pozice
Při použití kontejneru float layout je nutné explicitně specifikovat pozice komponent. Zadávají se přitom souřadnice levého dolního rohu komponenty. V našem konkrétním případě potřebujeme do plochy okna rozmístit devět tlačítek, takže si dopředu stanovíme jejich vzdálenosti od okraje (10 délkových jednotek) a současně i vzdálenosti mezi tlačítky (65 délkových jednotek):
BORDER=10 DISTANCE=65
Pozice komponent se určují při jejich konstrukci předáním nepovinného parametru pos. Samotné souřadnice jsou reprezentovány dvojicí popř. seznamem se dvěma prvky:
layout = FloatLayout() button = Button(text="1", size_hint=(1/4, 1/4), pos=(BORDER, BORDER)) layout.add_widget(button) button = Button(text="2", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER)) layout.add_widget(button) button = Button(text="3", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER)) layout.add_widget(button) ... ... ...
Výsledkem by měl být dialog, který vypadá následovně:
Opět si pochopitelně uvedeme celý zdrojový kód tohoto demonstračního příkladu:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího FloatLayout
# - dialog obsahuje devět tlačítek se stejnými vlastnostmi
# - explicitní rozmístění tlačítek
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
BORDER=10
DISTANCE=65
layout = FloatLayout()
button = Button(text="1", size_hint=(1/4, 1/4), pos=(BORDER, BORDER))
layout.add_widget(button)
button = Button(text="2", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER))
layout.add_widget(button)
button = Button(text="3", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER))
layout.add_widget(button)
button = Button(text="4", size_hint=(1/4, 1/4), pos=(BORDER, BORDER+DISTANCE))
layout.add_widget(button)
button = Button(text="5", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER+DISTANCE))
layout.add_widget(button)
button = Button(text="6", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER+DISTANCE))
layout.add_widget(button)
button = Button(text="7", size_hint=(1/4, 1/4), pos=(BORDER, BORDER+DISTANCE*2))
layout.add_widget(button)
button = Button(text="8", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER+DISTANCE*2))
layout.add_widget(button)
button = Button(text="9", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER+DISTANCE*2))
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (200, 200)
if __name__ == "__main__":
Application().run()
9. Programový výpočet pozice komponent
Díky tomu, že se o umístění komponent v kontejneru float layout stará přímo aplikace naprogramovaná v Pythonu, je možné pozice komponent vypočítat až za běhu aplikace. Podívejme se na poněkud umělý příklad, ve kterém se do plochy dialogu umístí devět tlačítek na stejnou diagonálu. Vzhledem k tomu, že je velikost tlačítek nastavena na jednu šestinu velikosti dialogu, budou se tlačítka částečně překrývat:
for i in range(0, 9):
button = Button(text=str(i+1), size_hint=(1/6, 1/6), pos=(BORDER+DISTANCE*i, BORDER+DISTANCE*i))
layout.add_widget(button)
Výsledná vizuální podoba dialogu:
Opět si, jak je již v tomto seriálu zvykem, uvedeme celý zdrojový kód tohoto demonstračního příkladu:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího FloatLayout
# - dialog obsahuje devět tlačítek se stejnými vlastnostmi
# - explicitní rozmístění tlačítek
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
BORDER=10
DISTANCE=30
layout = FloatLayout()
for i in range(0, 9):
button = Button(text=str(i+1), size_hint=(1/6, 1/6), pos=(BORDER+DISTANCE*i, BORDER+DISTANCE*i))
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (300, 300)
if __name__ == "__main__":
Application().run()
10. Kontejner typu relative layout
Dalším typem kontejneru, se kterým se v dnešním článku alespoň ve stručnosti seznámíme, je kontejner nazvaný relative layout. I při použití tohoto kontejneru se musí zadávat souřadnice jednotlivých komponent pomocí parametru pos předávaného do jejich konstruktoru, ovšem jedná se o souřadnice relativní, tj. vztažené k rodičovské komponentně nebo kontejneru. V případě, že je relative layout použit jako jediný kontejner v okně, bude výsledná vizuální podoba dialogu stejná, jako v případě float layout, ovšem pokud bude například relative layout vložen do jiného kontejneru, budou pozice odlišné. Konkrétní příklad s uceleným dialogem bude ukázán v navazujícím článku, ovšem již nyní je možné říci, že relative layout je pro mnoho účelů vhodnějším typem kontejneru, protože umožňuje velmi snadno sdružovat větší množství dialogů na jedinou plochu okna (nebo naopak rozdělit složitý dialog na řadu menších dialogů).
11. Příklad použití kontejneru relative layout
V případě, že je kontejner typu relative layout použit jako základní kontejner v původně prázdném okně, bude výsledkem stejná vizuální podoba dialogu, jako v případě kontejneru float layout, protože relativní souřadnice jsou vztaženy k počátku (0, 0):
BORDER=10 DISTANCE=65 layout = RelativeLayout() button = Button(text="1", size_hint=(1/4, 1/4), pos=(BORDER, BORDER)) layout.add_widget(button) button = Button(text="2", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER)) layout.add_widget(button) button = Button(text="3", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER)) layout.add_widget(button) ... ... ...
Obrázek 12: Explicitní rozmístění tlačítek na ploše dialogu, tentokrát ovšem s využitím kontejneru relative layout.
Úplný zdrojový kód demonstračního příkladu, který posloužil k vytvoření výše zobrazeného dialogu, vypadá následovně:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího RelativeLayout
# - dialog obsahuje devět tlačítek se stejnými vlastnostmi
# - explicitní rozmístění tlačítek
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
BORDER=10
DISTANCE=65
layout = RelativeLayout()
button = Button(text="1", size_hint=(1/4, 1/4), pos=(BORDER, BORDER))
layout.add_widget(button)
button = Button(text="2", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER))
layout.add_widget(button)
button = Button(text="3", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER))
layout.add_widget(button)
button = Button(text="4", size_hint=(1/4, 1/4), pos=(BORDER, BORDER+DISTANCE))
layout.add_widget(button)
button = Button(text="5", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER+DISTANCE))
layout.add_widget(button)
button = Button(text="6", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER+DISTANCE))
layout.add_widget(button)
button = Button(text="7", size_hint=(1/4, 1/4), pos=(BORDER, BORDER+DISTANCE*2))
layout.add_widget(button)
button = Button(text="8", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE, BORDER+DISTANCE*2))
layout.add_widget(button)
button = Button(text="9", size_hint=(1/4, 1/4), pos=(BORDER+DISTANCE*2, BORDER+DISTANCE*2))
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (200, 200)
if __name__ == "__main__":
Application().run()
12. Kontejner typu page layout
Posledním typem kontejneru, se kterým se v dnešním článku seznámíme, je kontejner nazvaný page layout. Tento kontejner umožňuje umístění komponent na jednotlivé „stránky“ (pages), přičemž v každém okamžiku je zobrazena jen jediná stránka a navíc je možné se mezi stránkami interaktivně přesunovat (listovat) buď pomocí myši nebo gesta na dotykovém displeji (což je pochopitelně mnohem přirozenější, protože se takto chová mnoho aplikací určených pro běh na mobilních telefonech). Technicky je listování stránkami provedeno takovým způsobem, že se mění absolutní pozice jednotlivých komponent. To má ovšem nepříjemný důsledek – komponenty z neviditelných stránek nejsou z dialogu vymazány, ale je nutné explicitně nastavovat pozadí na stránce, která je aktuálně zobrazena. Jak se tato operace provede si ukážeme v navazujících kapitolách, protože se v tomto případě pro vybarvení pozadí používá kreslicí plátno (canvas).
13. Příklady použití kontejneru page layout
Ukažme si nyní ten nejjednodušší, ale taktéž problematický, způsob použití kontejneru typu page layout. Po konstrukci kontejneru do něj umístíme devět tlačítek, a to naprosto stejným způsobem, jako jsme to dělali například u kontejnerů box layout nebo stack layout:
layout = PageLayout() button = Button(text="1") layout.add_widget(button) button = Button(text="2") layout.add_widget(button) ... ... ...
Po zobrazení takto vytvořeného dialogu se zobrazí pouze jediné tlačítko, protože další tlačítka jsou zobrazena na dalších stránkách:
Přesun na další stránku pomocí gesta (přesun stránky z pravého okraje dialogu) bude funkční, ale jen proto, že všechna tlačítka vyplňují celou plochu dialogu:
A takto vypadá úplný zdrojový kód demonstračního příkladu:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího PageLayout
# - PageLayout využívá výchozí (horizontální) orientaci
# - dialog obsahuje devět tlačítek se stejnými vlastnostmi
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.pagelayout import PageLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = PageLayout()
button = Button(text="1")
layout.add_widget(button)
button = Button(text="2")
layout.add_widget(button)
button = Button(text="3")
layout.add_widget(button)
button = Button(text="4")
layout.add_widget(button)
button = Button(text="5")
layout.add_widget(button)
button = Button(text="6")
layout.add_widget(button)
button = Button(text="7")
layout.add_widget(button)
button = Button(text="8")
layout.add_widget(button)
button = Button(text="9")
layout.add_widget(button)
return layout
def on_start(self):
Window.size = (400, 300)
if __name__ == "__main__":
Application().run()
Pokud budou ovšem tlačítka zmenšena, ukazuje se, že starší stránky jsou stále alespoň částečně viditelné, což není ideální (mimochodem, na stránku jsou přidány kontejnery, nikoli přímo tlačítka!):
layout = PageLayout() layout1 = AnchorLayout() button = Button(text="1", size_hint=(0.5, 0.5)) layout1.add_widget(button) layout.add_widget(layout1) layout2 = AnchorLayout() button = Button(text="2", size_hint=(0.5, 0.5)) layout2.add_widget(button) layout.add_widget(layout2) layout3 = AnchorLayout() button = Button(text="3", size_hint=(0.5, 0.5)) layout3.add_widget(button) layout.add_widget(layout3)
Výsledky vypadají takto:
Úplný zdrojový kód takto upraveného demonstračního příkladu:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího PageLayout
# - PageLayout využívá výchozí (horizontální) orientaci
# - dialog obsahuje trojici stránek s tlačítky
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.pagelayout import PageLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
class Application(App):
def build(self):
layout = PageLayout()
layout1 = AnchorLayout()
button = Button(text="1", size_hint=(0.5, 0.5))
layout1.add_widget(button)
layout.add_widget(layout1)
layout2 = AnchorLayout()
button = Button(text="2", size_hint=(0.5, 0.5))
layout2.add_widget(button)
layout.add_widget(layout2)
layout3 = AnchorLayout()
button = Button(text="3", size_hint=(0.5, 0.5))
layout3.add_widget(button)
layout.add_widget(layout3)
return layout
def on_start(self):
Window.size = (400, 300)
if __name__ == "__main__":
Application().run()
14. Složitější příklad s dvojicí dialogů, mezi nimiž je možné se přepínat
Kontejner typu page layout se poměrně často používá v situacích, v nichž je nutné na omezené ploše displeje (tedy například na mobilním telefonu) nějakým způsobem zobrazit komplikovaný dialog. Page layout v takových případech umožní rozdělení tohoto dialogu na menší části, mezi nimiž se může uživatel interaktivně přepínat. Tento způsob si (i když prozatím v ne zcela funkční podobě) nyní ukážeme.
Vytvoříme aplikaci, která bude obsahovat dvě části dialogu. V části první jsou umístěny ovládací prvky, které slouží pro zalogování do aplikace. Samotný dialog je v tomto případě tvořen kontejnerem, do kterého jsou vloženy ostatní ovládací prvky:
def login_page():
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
Druhá část dialogu je taktéž samostatná a obsahuje ovládací určené prvky pro nastavení barvy, resp. přesněji řečeno pro výběr barvy z barvového prostoru RGB:
def color_page():
layout = GridLayout(cols=5, padding=10, spacing=10)
slider_red = Slider(min=0, max=100, value=25, orientation="vertical")
layout.add_widget(slider_red)
slider_green = Slider(min=0, max=100, value=50, orientation="vertical")
layout.add_widget(slider_green)
slider_blue = Slider(min=0, max=100, value=75, orientation="vertical")
layout.add_widget(slider_blue)
label_rgb = Label(text="[size=40pt][b]T\ne\ns\nt[/b][/size]", markup=True)
layout.add_widget(label_rgb)
button = Button(text="Ok")
layout.add_widget(button)
return layout
Oba dialogy zkonstruované funkcemi login_page a color_page vložíme do kontejneru typu page layout, což znamená, že každý dialog bude umístěn na samostatnou stránku:
def build(self):
layout = PageLayout()
layout.add_widget(login_page())
layout.add_widget(color_page())
return layout
Výsledek po spuštění aplikace:
Problém se ukáže při nalistování druhé stránky, protože nedojde k úplnému překreslení stránky předchozí:
Řešení tohoto problému spočívá v nastavení barvy pozadí přes kreslicí plátno (canvas).
Opět si pochopitelně ukážeme úplný zdrojový kód tohoto demonstračního příkladu:
# Knihovna Kivy
#
# - GUI aplikace s jediným dialogem
# - definice dialogu využívajícího PageLayout
# - PageLayout využívá výchozí (horizontální) orientaci
# - dialog obsahuje trojici stránek s tlačítky
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.pagelayout import PageLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.slider import Slider
def login_page():
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 color_page():
layout = GridLayout(cols=5, padding=10, spacing=10)
slider_red = Slider(min=0, max=100, value=25, orientation="vertical")
layout.add_widget(slider_red)
slider_green = Slider(min=0, max=100, value=50, orientation="vertical")
layout.add_widget(slider_green)
slider_blue = Slider(min=0, max=100, value=75, orientation="vertical")
layout.add_widget(slider_blue)
label_rgb = Label(text="[size=40pt][b]T\ne\ns\nt[/b][/size]", markup=True)
layout.add_widget(label_rgb)
button = Button(text="Ok")
layout.add_widget(button)
return layout
class Application(App):
def build(self):
layout = PageLayout()
layout.add_widget(login_page())
layout.add_widget(color_page())
return layout
def on_start(self):
Window.size = (400, 300)
if __name__ == "__main__":
Application().run()
15. Kreslicí plátno (canvas)
V mnoha knihovnách a frameworcích pro tvorbu grafického uživatelského rozhraní existuje komponenta sloužící pro kreslení popř. pro manipulaci s jednotlivými pixely. Taková komponenta se již tradičně nazývá canvas neboli kreslicí plátno. Pravděpodobně nejpropracovanější je technologie kreslicího plátna v knihovně Tk (v Pythonu dostupné přes tkinter), ovšem vykreslování lze realizovat i v GTK, Qt atd.
V knihovně Kivy je kreslicí plátno součástí každého ovládacího prvku, což znamená, že v případě potřeby je možné například vykreslit vlastní styl tlačítka, změnit pozadí plochy kontejneru atd. A právě tento koncept, který je velmi důležitý, si popíšeme jak v navazujících kapitolách, tak i v následující části tohoto seriálu.
To, že je plátno součástí každého ovládacího prvku, lze otestovat snadno přímo v REPLu Pythonu:
$ uv run python Python 3.13.9 (main, Oct 14 2025, 00:00:00) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from kivy.uix.widget import Widget >>> x=Widget() >>> help(x.canvas)
Výsledkem by měla být nápověda k objektu typu Canvas:
Help on Canvas object: class Canvas(CanvasBase) | Canvas(**kwargs) | The important Canvas class. Use this class to add graphics or context | instructions that you want to be used for drawing. | | .. note:: | | The Canvas supports Python's ``with`` statement and its enter & exit | semantics. | | Usage of a canvas without the ``with`` statement:: | | self.canvas.add(Color(1., 1., 0)) | self.canvas.add(Rectangle(size=(50, 50))) | | Usage of a canvas with Python's ``with`` statement:: | | with self.canvas: | Color(1., 1., 0) | Rectangle(size=(50, 50)) | | Method resolution order: | Canvas | CanvasBase | InstructionGroup | Instruction | kivy._event.ObjectWithUid | builtins.object
16. Vykreslení čtverce na plochu kreslicího plátna
Zajímavé je, že na plátnu se neprovádí vykreslování tak, že by se zapisovaly jednotlivé příkazy typu „změn barvu“, „nakresli úsečku“ atd. Namísto toho se na plátno přidávají nové objekty, přičemž některé objekty představují barvu, jiné styl vykreslování a další pak geometrické obrazce, které se mají zobrazit. To například znamená, že pro zobrazení červeného čtverce musíme na plátno vložit objekty typu Color (předávají se barvové složky v prostoru RGBA) a Rectangle (předávají se rozměry čtverce a jeho pozice na plátnu):
class BasicCanvas(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.canvas.add(Color(0.9, 0.3, 0.3, 1))
self.canvas.add(Rectangle(pos=(100, 100), size=(100, 100)))
Po přidání obou objektů na plátno by mělo okno aplikace vypadat následovně:
Celý zdrojový kód tohoto příkladu má tvar:
# Knihovna Kivy
#
# - GUI aplikace s jediným oknem
# - v okně je umístěna kreslicí plocha
# - vykreslení barevného obdélníka
# - kreslení do canvasu s využitím metody add
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.graphics import Rectangle, Color
class BasicCanvas(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.canvas.add(Color(0.9, 0.3, 0.3, 1))
self.canvas.add(Rectangle(pos=(100, 100), size=(100, 100)))
class Application(App):
def build(self):
return BasicCanvas()
def on_start(self):
Window.size = (300, 300)
if __name__ == "__main__":
Application().run()
17. Využití správce kontextu (context manager)
Pro přidání objektů na kreslicí plátno se většinou namísto explicitního volání metody Canvas.add používá spíše správce kontextu (context manager). Zápis je v takovém případě nejenom jednodušší, ale zajistí i případné automatické uvolňování prostředků (resources) kreslicího plátna. Zdrojový kód z předchozí kapitoly je možné přepsat do této čitelnější podoby:
class BasicCanvas(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Color(0.9, 0.3, 0.3, 1)
Rectangle(pos=(100, 100), size=(100, 100))
Výsledek bude přesně odpovídat předchozímu příkladu:
Již naposledy si dnes ukážeme výpis celého zdrojového kódu demonstračního příkladu:
# Knihovna Kivy
#
# - GUI aplikace s jediným oknem
# - v okně je umístěna kreslicí plocha
# - vykreslení barevného obdélníka
# - kreslení do canvasu s využitím správce kontextu
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.graphics import Rectangle, Color
class BasicCanvas(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Color(0.9, 0.3, 0.3, 1)
Rectangle(pos=(100, 100), size=(100, 100))
class Application(App):
def build(self):
return BasicCanvas()
def on_start(self):
Window.size = (300, 300)
if __name__ == "__main__":
Application().run()
18. Obsah následující části seriálu
V navazující (konkrétně v pořadí již páté) části seriálu o tvorbě grafického uživatelského rozhraní s využitím knihovny Kivy si ukážeme další možnosti, které kreslicí plátno vývojářům nabízí. Z pohledu programátora se jedná o velmi užitečnou technologii, která například umožňuje relativně snadno vyvíjet aplikace typu CAD, vykreslovat interaktivní grafy apod.
19. Repositář s demonstračními příklady
Demonstrační příklady, s nimiž jsme se 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/ - Dokumentace k frameworku Kivy: BoxLayout
https://kivy-fork.readthedocs.io/en/latest/api-kivy.uix.boxlayout.html - Dokumentace k frameworku Kivy: Box Layout
https://kivy.org/doc/stable/api-kivy.uix.boxlayout.html#module-kivy.uix.boxlayout - Dokumentace k frameworku Kivy: Grid Layout
https://kivy.org/doc/stable/api-kivy.uix.gridlayout.html#module-kivy.uix.gridlayout - Dokumentace k frameworku Kivy: Stack Layout
https://kivy.org/doc/stable/api-kivy.uix.stacklayout.html#module-kivy.uix.stacklayout - Dokumentace k frameworku Kivy: Anchor Layout
https://kivy.org/doc/stable/api-kivy.uix.anchorlayout.html - Dokumentace k frameworku Kivy: PageLayout
https://kivy.org/doc/stable/api-kivy.uix.pagelayout.html - Dokumentace k frameworku Kivy: Float Layout
https://kivy.org/doc/stable/api-kivy.uix.floatlayout.html - Dokumentace k frameworku Kivy: Relative Layout
https://kivy.org/doc/stable/api-kivy.uix.relativelayout.html - Dokumentace k frameworku Canvas
https://kivy.org/doc/stable/api-kivy.graphics.instructions.html - Canvas in Kivy- Python
https://www.geeksforgeeks.org/python/python-canvas-in-kivy/ - Kivy – Canvas
https://www.tutorialspoint.com/kivy/kivy-canvas.htm - Delphi (software)
https://en.wikipedia.org/wiki/Delphi_(software) - Visual Basic (classic)
https://en.wikipedia.org/wiki/Visual_Basic_(classic)
















