Hlavní navigace

PyWebIO: interaktivní webové dialogy a formuláře v čistém Pythonu

17. 3. 2022
Doba čtení: 25 minut

Sdílet

 Autor: převzato s dovolením od PyWebIO
V mnoha situacích potřebujeme vytvořit aplikaci s formuláři a dialogy – tedy aplikaci s GUI. Pokud používáme Python, můžeme využít knihovny Tkinter, PyObject, PyQt/PySide atd. Nebo je možné vytvořit webovou aplikaci.

Obsah

1. PyWebIO: interaktivní webové dialogy a formuláře naprogramované v čistém Pythonu

2. Klasické knihovny pro tvorbu GUI: systém událostí popř. signálů+slotů

3. Koncept vstupu a výstupu (I/O) namísto architektury založené na systému událostí

4. Instalace knihovny PyWebIO

5. Zobrazení informací na webové stránce – modul pywebio.output

6. Tabulky

7. Informace o probíhajících operacích, zobrazení zprávy

8. Zobrazení fragmentu dokumentu zapsaného v HTML, Markdownu i ve formě zdrojového kódu

9. Animace průběhu výpočtu

10. Animace zobrazená při načítání nebo v průběhu výpočtu

11. Vstupní textové pole

12. Sdružení několika vstupních polí do jediného formuláře

13. Specifikace typu vstupních hodnot, rozlišení povinných a nepovinných hodnot

14. Rádiová tlačítka (přepínače)

15. Výběrové boxy

16. Výběr z několika nabízených variant

17. Posuvník

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

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

20. Odkazy na Internetu

1. PyWebIO: interaktivní webové dialogy a formuláře naprogramované v čistém Pythonu

Jak již bylo napsáno v perexu dnešního článku, existují situace, kdy vývojář potřebuje vytvořit aplikaci s formuláři a dialogy, popř. i s grafy, tedy aplikaci s grafickým uživatelským rozhraním. V případě, že používá programovací jazyk Python, je možné pro tento účel využít již popsané knihovny Tkinter, PyObject, PyQt/PySide atd. (viz též seznam článků vydaných v rámci seriálu o grafickém uživatelském rozhraní v Pythonu). Alternativně je ovšem možné vytvořit lokálně či vzdáleně použitelnou webovou aplikaci, a to čistě v Pythonu: tedy bez explicitní práce s HTML, CSS a JavaScriptem. Pro tento účel poměrně dobře poslouží hned několik zajímavých knihoven a frameworků. My se dnes zaměříme na asi vůbec nejsnadněji použitelnou knihovnu nazvanou velmi příhodně PyWebIO.

Obrázek 1: Obrazovka nástroje Pygubu designer určeného pro návrh grafického uživatelského rozhraní aplikací vytvářených v Pythonu. Výsledkem je kód založený na knihovně Tkinter.

Na tomto místě se ve stručnosti zmiňme o dvou projektech s podobným cílem. První z těchto projektů se jmenuje Streamlit a budeme se jím zabývat v samostatném článku. A druhý podobný projekt se jmenuje pglet (ten dokonce podporuje větší množství programovacích jazyků).

Obrázek 2: Jednoduchá aplikace využívající knihovnu PySide.

Poznámka: interně se pochopitelně technologie HTML, CSS a JavaScript ve webové aplikaci musí používat (stejně jako webový server na straně Pythonu), ovšem programátor se s těmito technologiemi nemusí (pokud vyloženě nepotřebuje) při použití knihovny PyWebIO setkat. Veškerá práce s GUI se z pohledu programátora omezuje na několik funkcí určených pro vstup dat popř. pro jejich výstup.

2. Klasické knihovny pro tvorbu GUI: systém událostí popř. signálů+slotů

Většina knihoven určených pro tvorbu grafického uživatelského rozhraní (v Pythonu) je založena buď na systému událostí nebo na takzvaných signálech a slotech. V obou případech se na jednu stranu jedná o velmi flexibilní způsob tvorby GUI, ovšem při tvorbě jednodušších formulářů a dialogů může být tato flexibilita někdy na obtíž, protože se architektura aplikace musí (alespoň do jisté míry) přizpůsobit celému konceptu GUI. Ostatně si to můžeme ukázat na jednoduchém příkladu naprogramovaném s využitím snad nejsnadněji použitelné „klasické“ knihovny pro tvorbu GUI. Jedná se o knihovnu nazvanou AppJar:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        app.infoBox("Ok, Ok", "Ok button pressed")
 
 
app = gui()
 
app.addLabel("title", "Hello world!", colspan=2)
 
app.addButtons(["Ok", "Quit"], onButtonPress, 1, 0)
 
app.go()

Obrázek 3: Screenshot jednoduché aplikace představované předchozím skriptem.

V knihovně PySide naproti tomu může každý ovládací prvek (widget) generovat signály, a to konkrétně v případě vzniku nějaké události (tou může být například stisk tlačítka, změna pozice posuvníku, změna velikosti okna atd.) nebo změny stavu widgetu. Signály mohou být napojené na takzvané sloty, což je pojmenování pro funkce, které mohou reagovat na příchozí signál. V knihovně Qt, nad níž je PySide postaven, jsou signály zpracovávány nativními funkcemi, PySide ovšem celý koncept signálů a slotů dokáže „obalit“ takovým způsobem, že sloty jsou běžnými Pythonovskými funkcemi či metodami. Musíme však explicitně specifikovat propojení mezi signálem (resp. jeho typem) a slotem:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# callback funkce
def closeApplication():
    print("Closing...")
    sys.exit(0)
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        self.resize(320, 240)
        self.setWindowTitle("Quit Button")
 
        # tlačítko
        button = QtGui.QPushButton("Quit", self)
        button.resize(button.sizeHint())
        button.setToolTip("Immediately quit this application")
 
        # navázání akce na signál
        button.clicked.connect(closeApplication)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

Obrázek 4: Tlačítko umístěné v oknu předchozího příkladu.

3. Koncept vstupu a výstupu (I/O) namísto architektury založené na systému událostí

Knihovna PyWebIO je navržena takovým způsobem, aby vývojáře v co největší míře odstínila od nutnosti „otočení“ logiky aplikace, a to jen proto, aby v ní bylo bylo možné použít grafické uživatelské rozhraní. Autoři se naopak snažili o to, aby byla v programovém kódu zachována původní logika typu „dotaz na údaje zadávané uživatelem“ → „výpočet a odpověď vypsaná uživateli“. Jedná se o koncept, na němž je postavena klasická příkazová řádka a částečně i nástroje typu „diář“, tedy například Jupyter Notebook.

Podívejme se nyní na triviální skript napsaný v Pythonu, po jehož spuštění se počítač uživatele (postupně) zeptá na zadání vstupních hodnot. Na základě těchto hodnot je proveden výpočet a výsledek je zobrazen do terminálu. Povšimněte si, že počítač v tomto případě vede s uživatelem dialog, jenž je řízený skriptem. Jedná se skutečně o triviální příklad, v němž nemá uživatel žádnou možnost dalšího ovlivnění výpočtu (na rozdíl od většiny aplikací ovládaných z příkazového řádku, kde je naopak většinou vše řízeno uživatelem):

# Body Mass Index calculator
 
print("Mass (kg): ")
mass = int(input())
 
print("Height (cm): ")
height = int(input())
 
# převod výšky na metry
height = height / 100.0
 
# výpočet (bez jakýchkoli kontrol)
bmi = mass / (height * height)
 
# výpis výsledku
print("BMI = ", bmi)

Obrázek 5: Dialog počítače s uživatelem.

Tento příklad lze snadno převést do formy využívající knihovnu PyWebIO. V případě, že vynecháme příkaz import (ten je zde ovšem nezbytný), spočívá celý přepis skriptu pouze v náhradě funkce print za funkci put_text. Žádné další úpravy nejsou nutné – a přece je výsledkem interaktivní „webová aplikace“(!):

# Body Mass Index calculator
 
put_text("Mass (kg): ")
mass = int(input())
 
put_text("Height (cm): ")
height = int(input())
 
# převod výšky na metry
height = height / 100.0
 
# výpočet (bez jakýchkoli kontrol)
bmi = mass / (height * height)
 
# výpis výsledku
put_text("BMI = ", bmi)

Obrázek 6: Webové rozhraní skriptu se zobrazeným textem.

Na základě této ukázky by se mohlo zdát, že PyWebIO pouze umožňuje změnit způsob chování interaktivního vstupu (funkce input) a výstupu (funkce print), zatímco samotný skript nebude mít možnost žádným dalším způsobem ovlivnit vzhled webové aplikace například během výpočtu. Ovšem ve skutečnosti jsou možnosti PyWebIO širší, což naznačuje následující skript, jenž zobrazí „teploměr“ (tedy neinteraktivní prvek uživatelského rozhraní), jehož hodnota postupně roste on 0 do 100% (v tomto konkrétním případě jsou výpočty simulovány funkcí time.sleep – tu by však pochopitelně bylo možné nahradit reálným kódem):

put_processbar('bar');
 
for i in range(1, 11):
    set_processbar('bar', i / 10)
    time.sleep(0.1)
Poznámka: podobně je koncipovaný i projekt Zenity, což je nástroj volatelný z příkazové řádky. Tomuto nástroji se předají informace o tom, jaké ovládací prvky má zobrazit a popř. i výchozí data v těchto prvcích. Následně se zobrazí dialog, čeká se na akci uživatele a následně Zenity vrátí výsledek. Zenity však není jediný nástroj tohoto typu. Existuje například i nástroj Dialog, i když způsob zobrazení formulářů a dialogů je realizován s využitím odlišných technologií.

Na tomto místě je dobré upozornit na fakt, že je zřejmé, že koncept založený na prostém vstupu a výstupu není dostatečně obecný, aby se s jeho využitím mohly tvořit i aplikace se složitěji pojatým ovládáním (například webové hry nebo plně interaktivní aplikace typu Google Doc). Ovšem až překvapivé množství webových aplikací se skutečně skládá ze sady formulářů a dialogů. Příkladem jsou servery typu Root.cz s možností zadání jednoduché ankety, ale například i webová aplikace určená pro vyplňování daňových přiznání. PyWebIO je navíc určeno nikoli pouze pro tvorbu výše zmíněných „plnohodnotných“ webových aplikací, ale je například oblíben vývojáři z oblasti strojového učení (machine learning), kde je mnohdy potřeba zadat vstupní parametry a následně například vykreslit výsledek analýz či výpočtů (navíc mohou být odborníci na strojové učení odstíněni od „pohyblivých cílů“ typu Angular/React/Vue atd.).

4. Instalace knihovny PyWebIO

Knihovna PyWebIO je nabízena přes PyPi, takže její instalace by měla být jednoduchá a přímočará. Knihovnu nainstalujeme pro aktuálně přihlášeného uživatele:

$ pip3 install --user pywebio
 
Collecting pywebio
  Downloading pywebio-1.5.2.tar.gz (450 kB)
     |████████████████████████████████| 450 kB 953 kB/s
  Preparing metadata (setup.py) ... done
Collecting tornado>=5.0
  Downloading tornado-6.1-cp38-cp38-manylinux2010_x86_64.whl (427 kB)
     |████████████████████████████████| 427 kB 1.6 MB/s
Collecting user-agents
  Downloading user_agents-2.2.0-py3-none-any.whl (9.6 kB)
Collecting ua-parser>=0.10.0
  Downloading ua_parser-0.10.0-py2.py3-none-any.whl (35 kB)
Building wheels for collected packages: pywebio
  Building wheel for pywebio (setup.py) ... done
  Created wheel for pywebio: filename=pywebio-1.5.2-py3-none-any.whl size=459628 sha256=3a86f8dfcb5992e4f1cd5c76cede3aceecaf25d07edde9f57848824cb6500c0c
  Stored in directory: /home/ptisnovs/.cache/pip/wheels/e7/dc/43/f395fa089831aeb5fa3eb3c577ec3ea53636b45fb03a32c301
Successfully built pywebio
Installing collected packages: ua-parser, user-agents, tornado, pywebio
Successfully installed pywebio-1.5.2 tornado-6.1 ua-parser-0.10.0 user-agents-2.2.0
Poznámka: povšimněte si, že se kromě vlastní knihovny PyWebIO nainstalovaly i další balíčky, zejména balíček Tornado, k jehož významu se ještě dostaneme.

5. Zobrazení informací na webové stránce – modul pywebio.output

Knihovna PyWebIO je rozdělena do několika balíčků (modulů). Nejprve se seznámíme se základními vlastnostmi balíčku nazvaného pywebio.output. Jak již název tohoto balíčku naznačuje, je určen pro zajištění výstupu informací přes webové rozhraní (tedy přes dynamicky generovanou a postupně aktualizovanou webovou stránku). Nejjednodušší je výstup (zobrazení) textu, což je realizováno funkcí nazvanou put_text. V nejjednodušší podobě může textový výstup vypadat následovně:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
out.put_text("Hello world!")

Po spuštění tohoto skriptu by se mělo otevřít okno s webovým prohlížečem popř. (pokud je již prohlížeč spuštěn) by se měl otevřít nový tab, jenž bude obsahovat pouze zprávu zobrazenou uživateli:

Obrázek 7: Webové rozhraní skriptu se zobrazeným textem.

Poznámka: je dobré si uvědomit, kolik operací vlastně muselo proběhnout na pozadí. Musel se například spustit webový server, nějakým způsobem zajistit otevření okna (či tabu) prohlížeče, poslat prohlížeči kostru aplikace a následně zajistit komunikaci mezi backendem a frontendem – tato komunikace je oboustranná a probíhá prakticky neustále (implicitně jsou použity Web Sockety). Skript tak dokáže například zareagovat i na situaci, kdy je okno/tab prohlížeče uzavřeno:
Traceback (most recent call last):
  File "13_input.py", line 11, in <module>
    mass = int(inp.input())
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/input.py", line 257, in input
    return single_input(item_spec, valid_func, preprocess_func, onchange_func)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/session/__init__.py", line 283, in inner
    return run_as_function(gen)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/utils.py", line 296, in run_as_function
    res = gen.send(res)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/io_ctrl.py", line 260, in single_input
    data = yield input_control(spec=spec,
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/session/__init__.py", line 283, in inner
    return run_as_function(gen)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/utils.py", line 296, in run_as_function
    res = gen.send(res)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/io_ctrl.py", line 280, in input_control
    data = yield input_event_handle(item_valid_funcs, form_valid_funcs, preprocess_funcs, onchange_funcs)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/session/__init__.py", line 283, in inner
    return run_as_function(gen)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/utils.py", line 296, in run_as_function
    res = gen.send(res)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/io_ctrl.py", line 334, in input_event_handle
    event = yield next_client_event()
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/session/__init__.py", line 283, in inner
    return run_as_function(gen)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/utils.py", line 296, in run_as_function
    res = gen.send(res)
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/session/__init__.py", line 290, in next_client_event
    res = yield get_current_session().next_client_event()
  File "/home/ptisnovs/.local/lib/python3.8/site-packages/pywebio/session/threadbased.py", line 138, in next_client_event
    raise SessionClosedException
pywebio.exceptions.SessionClosedException

6. Tabulky

Velmi často je nutné vhodnou formou zobrazit výsledek nějakého výpočtu či simulace, přičemž tento výsledek má tabulární podobu (typicky se jedná o 2D tabulku). Knihovna PyWebIO pochopitelně podporuje i zobrazení tabulárních dat. Taková data mohou být v programovacím jazyce Python reprezentována například jako seznam seznamů, seznam n-tic, jako vnořené n-tice atd. Zobrazení obsahu těchto datových struktur na dynamicky vytvářené a aktualizované webové stránce je triviální – viz též zdrojový kód dnešního druhého demonstračního příkladu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
out.put_table([
    ['Language', 'Ratings'],
    ['C', '15.95'],
    ['Java', '13.48'],
    ['Python', '10.47'],
    ['C++', '7.11'],
    ['C#', '4.58'],
    ['Visual Basic', '4.12'],
    ['JavaScript', '2.54'],
    ['PHP', '2.49'],
    ['R', '2.37'],
    ['SQL', '1.76'],
    ['Go', '1.46'],
    ['Swift', '1.38'],
    ['Perl', '1.30'],
    ['Assembly language', '1.30'],
    ['Ruby', '1.24'],
    ['MATLAB', '1.10'],
    ['Groovy', '0.99'],
    ['Rust', '0.92'],
    ['Objective-C', '0.85'],
    ['Dart', '0.77'],
])

Obrázek 8: Webové rozhraní skriptu se zobrazenou tabulkou.

Namísto statických dat použitých v předchozím příkladu je pochopitelně možné zobrazit i výsledek nějakého výpočtu, což je ukázáno v dalším skriptu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
values = [(x, 1.0/x) for x in range(1, 20)]
 
out.put_table(values)
Poznámka: v tomto případě je výsledek výpočtu uložen ve formě seznamu n-tic.

Obrázek 9: Webové rozhraní skriptu se zobrazenou tabulkou.

Data v tabulce lze v případě potřeby i naformátovat:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
values = [(x, "{:5.3f}".format(1.0/x)) for x in range(1, 20)]
 
out.put_table(values)

Obrázek 10: Webové rozhraní skriptu se zobrazenou tabulkou.

7. Informace o probíhajících operacích, zobrazení zprávy

Mezi další pasivní ovládací prvky, které lze na webové stránce použít, jsou prvky, které uživatele vizuálně informují o probíhající operaci (například o výpočtu, načítání dat atd.). U těchto prvků je možné volit jednu z osmi logických jmen barev:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
for color in ('primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark'):
    out.put_text(color, color)
    out.put_loading(shape='border', color=color)

Obrázek 11: Webové rozhraní skriptu s osmi zobrazenými prvky s informací o probíhající (prozatím nedokončené) operaci.

V mnoha případech je nutné zobrazit uživateli zprávu s určitým významem (sémantikou). V knihovně PyWebIO lze vypsat informační zprávy, dále zprávu o úspěšně dokončené operaci, zprávu s varováním i zprávu o chybě. Výpis těchto zpráv je stejně snadný jako výpis běžného textu – liší se jen jméno použité funkce:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
out.put_info("Info message")
out.put_success("Success message")
out.put_warning("Warning message")
out.put_error("Error message")

Obrázek 12: Čtyři typy zpráv podporovaných knihovnou PyWebIO.

8. Zobrazení fragmentu dokumentu zapsaného v HTML, Markdownu i ve formě zdrojového kódu

Část údajů zobrazená ve webové aplikaci může být zapsána přímo v HTML (například se může jednat o část vytvořenou nějakým šablonovacím systémem). Pro zobrazení fragmentu HTML se používá výstupní funkce put_html:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
html = """
<h1>Header</h1>
 
<table>
  <tr>
    <td style='background:#ff8080'>Cell</td>
    <td style='background:#ffff80'>Cell</td>
  </tr>
</table>
"""
 
out.put_html(html)

Obrázek 13: Fragment HTML zobrazený ve webové aplikaci.

Stejně snadno lze zobrazit dokument napsaný v Markdownu. Namísto funkce put_html se v tomto případě použije funkce nazvaná put_markdown:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
markdown = '''
Markdown rendering
==================
 
Lorem ipsum
-----------
 
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
'''
 
out.put_markdown(markdown)

Obrázek 14: Dokument zapsaný v Markdownu zobrazený ve webové aplikaci.

A konečně je možné ve webové aplikaci zobrazit zdrojový kód s obarvenou syntaxí. Pro tento účel se používá funkce put_code, které se předává i jméno jazyka, v němž jsou zdrojové kódy zapsány:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
 
code = """
# Body Mass Index calculator
 
print("Mass (kg): ")
mass = int(input())
 
print("Height (cm): ")
height = int(input())
 
# předod výšky na metry
height = height / 100.0
 
# výpočet (bez jakýchkoli kontrol)
bmi = mass / (height * height)
 
# výpis výsledku
print("BMI = ", bmi)
"""
 
out.put_code(code, language="python", rows=15)
 
code2 = r"""
package main
 
import "fmt"
 
// I represents a new interface type (in this case empty interface)
type I interface{}
 
// T represents an user-defined data type
type T struct{}
 
func main() {
        var t *T
        if t == nil {
                fmt.Println("t is nil")
        } else {
                fmt.Println("t is not nil")
        }
        var i I = t
        if i == nil {
                fmt.Println("i is nil")
        } else {
                fmt.Println("i is not nil")
        }

}
"""
 
out.put_code(code2, language="go", rows=15)

Obrázek 15: Dva zdrojové kódy zobrazené ve webové aplikaci.

Poznámka: k zobrazení zdrojového kódu se ještě vrátíme v navazujícím článku. Knihovna PyWebIO totiž obsahuje i poměrně sofistikovaný textový editor, což je interně textové pole na webové stránce, které ovšem kromě dalších možností nabízí i zvýraznění syntaxe zdrojových kódů či konfiguračních souborů.

9. Animace průběhu výpočtu

Se způsobem zobrazení animace ve chvíli, kdy se načítají data nebo se provádí výpočet, jsme se již setkali, takže si jen v krátkosti připomeňme, že pro tento účel se používá ovládací prvek process bar, jehož aktuální hodnotu v rozsahu 0 až 1 je možné programově měnit. V případě potřeby je možné využít i větší množství těchto ovládacích prvků (například pro zobrazení průběhu dílčích operací):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
import time
 
 
out.put_processbar('bar');
 
for i in range(1, 11):
    out.set_processbar('bar', i / 10)
    time.sleep(0.1)

Obrázek 16: Animace průběhu výpočtu.

10. Animace zobrazená při načítání nebo v průběhu výpočtu

V případě, že není zřejmé, jak dlouho má nějaká operace trvat (a tedy není možné použít processbar), lze využít ovládací prvek nazvaný loading, který na ploše webové aplikace zobrazí animaci oznamující, že probíhá nějaká operace. Po dokončení této operace se v aktuálním kontextu pouze vypíše informace o dokončení (či jakákoli další data), jak je ukázáno v následujícím příkladu (s kontextem lze v Pythonu nejsnáze pracovat s využitím bloku with):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
import time
 
 
with out.put_loading(shape='border', color='primary'):
    time.sleep(5)
    out.put_text("Done")

Obrázek 17: Jeden snímek animace zobrazené při načítání nebo v průběhu výpočtu.

Podporovány jsou i sémantické názvy barev:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.output as out
 
import time
 
 
i = 0
 
for color in ('primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark'):
    with out.put_loading(shape='border', color=color):
        time.sleep(1)
        out.put_text(i)
        i += 1
 
out.put_text("Done")

Obrázek 18: Specifikace barvy prvku.

11. Vstupní textové pole

Pro vstup textových popř. pouze číselných údajů slouží vstupní textové pole, které se zobrazuje funkcí s plným jménem pywebio.input.input. V případě, že je tato funkce zavolána, zobrazí se na webové stránce vstupní pole a teprve po zadání a potvrzení údajů bude program pokračovat dalším zapsaným příkazem. Přepis původní aplikace určené pro ovládání z terminálu do „webové podoby“ může vypadat následovně:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
# Body Mass Index calculator
 
out.put_text("Mass (kg): ")
mass = int(inp.input())
 
out.put_text("Height (cm): ")
height = int(inp.input())
 
# převod výšky na metry
height = height / 100.0
 
# výpočet (bez jakýchkoli kontrol)
bmi = mass / (height * height)
 
# výpis výsledku
out.put_info("BMI = ", bmi)

Obrázek 19: Vstupní textové pole zobrazené ve webové aplikaci.

12. Sdružení několika vstupních polí do jediného formuláře

Velmi často se setkáme s požadavkem na zadání většího množství údajů do několika vstupních polí. S využitím funkce pywebio.input.input_group je možné sdružit libovolné množství vstupních prvků, tedy i textových polí, a zobrazit je společně. Po zápisu a potvrzení údajů se vrátí slovník, jehož klíče jsou specifikovány při tvorbě vstupních polí parametrem name:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
# Body Mass Index calculator
 
info = inp.input_group("Entry",[
  inp.input("Mass (kg)", name="mass"),
  inp.input("Height (cm)", name="height")
])
 
mass = float(info["mass"])
height = float(info["height"])
 
# převod výšky na metry
height = height / 100.0
 
# výpočet (bez jakýchkoli kontrol)
bmi = mass / (height * height)
 
# výpis výsledku
out.put_info("BMI = ", bmi)

Výsledkem by měl být následující formulář:

Obrázek 20: Dvojice vstupních polí sdružená do jediného formuláře.

13. Specifikace typu vstupních hodnot, rozlišení povinných a nepovinných hodnot

Mnohá vstupní pole mají akceptovat pouze omezenou množinu znaků popř. zadávaných hodnot. Příkladem může být náš skript, který po uživateli vyžaduje zápis hmotnosti a výšky. V obou případech se jedná o číselné údaje, takže má smysl omezit množinu znaků a jejich kombinací, které může uživatel v těchto dvou vstupních polích použít. Konkrétně je možné u vstupních polí specifikovat, že lze povolit pouze zadání čísel, a to s využitím nepovinného parametru type (viz zvýrazněnou část zdrojového kódu):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
# Body Mass Index calculator
 
info = inp.input_group("Entry",[
  inp.input("Mass (kg)", name="mass", type=inp.NUMBER),
  inp.input("Height (cm)", name="height", type=inp.NUMBER)
])
 
mass = info["mass"]
height = info["height"]
 
# převod výšky na metry
height = height / 100.0
 
# výpočet (bez jakýchkoli kontrol)
bmi = mass / (height * height)
 
# výpis výsledku
out.put_info("BMI = ", bmi)

Obrázek 21: Vstupní pole pro vstup číselných údajů.

Dále je velmi vhodné specifikovat, které vstupní hodnoty se musí vyplnit a které hodnoty jsou naopak nepovinné. K zadání této informace slouží nepovinný parametr required. Opět se podívejte na zvýrazněnou část zdrojového kódu, v níž je tento parametr použit:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
# Body Mass Index calculator
 
info = inp.input_group("Entry",[
  inp.input("Mass (kg)", name="mass", type=inp.NUMBER, required=True),
  inp.input("Height (cm)", name="height", type=inp.NUMBER, required=True)
])
 
mass = info["mass"]
height = info["height"]
 
# převod výšky na metry
height = height / 100.0
 
# výpočet (bez jakýchkoli kontrol)
bmi = mass / (height * height)
 
# výpis výsledku
out.put_info("BMI = ", bmi)

Obrázek 22: Vstupní pole, které je nutné vyplnit.

14. Rádiová tlačítka (přepínače)

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 klasických tlačítek (Button) 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. Rádiová tlačítka jsou podporována i knihovnou PyWebIO, o čemž se ostatně můžeme velmi snadno přesvědčit spuštěním následujícího skriptu. Měl by se zobrazit jednoduchý formulář s třemi nabídkami a taktéž s tlačítky Submit a Reset:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
answer = inp.radio(label="test", options=["varianta 1", "varianta 2", "varianta 3"])
 
out.put_info("Odpověď")
out.put_text(answer)

Obrázek 23: Přepínače zobrazené ve webové aplikaci.

15. Výběrové boxy

Dalším typem grafického ovládacího prvku (widgetu) je takzvaný checkbutton, dnes poněkud nepřesně nazývaný checkbox. Od obyčejného tlačítka se tento widget liší především tím, že je vizuálně patrný jeho stav – nastaveno/nenastaveno. Tento typ tlačítek 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 nejjednodušším případě se přepínací tlačítko vytvoří následovně:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
answer = inp.checkbox(label="test", options=["varianta 1", "varianta 2", "varianta 3"])
 
out.put_info("Odpověď")
out.put_text(answer)

Obrázek 24: Výběrové boxy zobrazené ve webové aplikaci.

16. Výběr z několika nabízených variant

Výběr akce či odpovědi z několika předem známých variant lze realizovat i odlišným způsobem – použitím ovládacího prvku actions. Ve skutečnosti se v tomto případě zobrazí několik tlačítek, z nichž je (logicky) možné vybrat pouze jediné. Tlačítka se funkci actions předávají v pojmenovaném parametru buttons:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
answer = inp.actions(label="test", buttons=["varianta 1", "varianta 2", "varianta 3"])
 
out.put_info("Odpověď")
out.put_text(answer)

Obrázek 25: Výběrová tlačítka zobrazené ve webové aplikaci.

17. Posuvník

Poslední ovládací prvek, který si dnes popíšeme, se nazývá slider, ovšem v jiných knihovnách se například setkáme i s označením slider. Jedná se o interaktivní ovládací prvek, který uživateli umožňuje výběr hodnoty v zadaném rozsahu (a popř. i se specifikovaným krokem). Výchozí hodnota posuvníku se nastavuje parametrem value:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pywebio.input as inp
import pywebio.output as out
 
 
weight = inp.slider(label="Váha", value=75, min_value=30, max_value=150)
 
out.put_info("Váha")
out.put_text(weight)

Obrázek 26: Posuvník zobrazený ve webové aplikaci.

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

V navazujícím článku se zaměříme především na způsoby deklarace složitějších formulářů s větším množstvím vstupních prvků, dále se správou sezení (session) a taktéž na použití různých forem výstupů. Knihovnu PyWebIO je totiž možné v případě potřeby použít společně s dalšími knihovnami. Například lze relativně jednoduše realizovat vykreslení grafů do dynamicky generované webové stránky. Pro tento účel lze využít například knihovnu Matplotlib, ale taktéž knihovny Bokeh, pyecharts, plotly, pyg2plot či cutecharts.py.

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

Zdrojové kódy všech dnes popsaných demonstračních příkladů určených pro programovací jazyk Python 3 byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Demonstrační příklad Stručný popis příkladu Cesta
1 01_basic_output.py zobrazení běžného textu ve webovém prohlížeči https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/01_ba­sic_output.py
2 02_table.py zobrazení tabulky ve webovém prohlížeči https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/02_table.py
3 03_table.py programová příprava tabulky zobrazené ve webovém prohlížeči https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/03_table.py
4 04_table.py programová příprava tabulky zobrazené ve webovém prohlížeči https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/04_table.py
5 05_color.py podpora pro symbolické názvy barev https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/05_color.py
6 06_message.py výpis ostylovaných zpráv do webové stránky https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/06_message.py
7 07_put_html.py podpora pro výstup HTML kódu z PyWebIO https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/07_put_html­.py
8 08_put_markdown.py výpis textu (dokumentu) napsaného ve značkovacím jazyku Markdown https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/08_put_mar­kdown.py
9 09_put_code.py výpis zdrojového kódu se zvýrazněním syntaxe https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/09_put_co­de.py
10 10_progress_bar.py animované zobrazení průběhu operace https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/10_pro­gress_bar.py
11 11_loading.py informace o výpočtu či načítání stránky https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/11_loading.py
12 12_loading.py informace o výpočtu či načítání stránky https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/12_loading.py
13 13_input.py vstupní textové pole https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/13_input.py
14 14_input.py vylepšená vstupní textová pole https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/14_input.py
15 15_input_numbers.py kontrola korektnosti numerických údajů https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/15_in­put_numbers.py
16 16_input_numbers_required.py povinné vstupní parametry https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/16_in­put_numbers_required.py
17 17_radio.py přepínače https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/17_radio.py
18 18_checkbox.py výběrové boxy https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/18_chec­kbox.py
19 19_actions.py skupina akcí https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/19_actions.py
20 20_slider.py interaktivní posuvník https://github.com/tisnik/most-popular-python-libs/blob/master/pywebio/20_slider.py

20. Odkazy na Internetu

  1. Low code Python web framework
    https://www.pyweb.io/
  2. Repositář projektu
    https://github.com/pywebio/PyWebIO/
  3. Getting Started
    https://www.pyweb.io/tutorial.html
  4. Dokumentace
    https://pywebio.readthedoc­s.io/en/latest/
  5. Why PyWebIO?
    https://github.com/pywebi­o/PyWebIO/wiki/Why-PyWebIO%3F
  6. PyWebIO demos
    https://pywebio-demos.pywebio.online/
  7. PyWebIO Chart Gallery
    https://pywebio-charts.pywebio.online/
  8. Awesome Python
    https://awesome-python.com/
  9. A complete guide to web development in Python
    https://www.educative.io/blog/web-development-in-python
  10. Python Web Development Tutorials
    https://realpython.com/tutorials/web-dev/
  11. What is Flask Python
    https://pythonbasics.org/what-is-flask-python/
  12. CherryPy
    https://cherrypy.dev/
  13. Projekt Zenity
    https://wiki.gnome.org/Pro­jects/Zenity
  14. Nástroj Dialog
    http://invisible-island.net/dialog/
  15. Plotly
    https://plotly.com/
  16. Bokeh
    https://bokeh.org/
  17. pyecharts
    https://github.com/pyechar­ts/pyecharts/blob/master/RE­ADME.en.md
  18. Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib
    https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib/
  19. Alternatives to PyWebIO
    https://stackshare.io/pywe­bio/alternatives
  20. The fastest way to build and share data apps – Streamlit
    https://streamlit.io/
  21. Dash Enterprise
    https://plotly.com/dash/
  22. pglet
    https://pglet.io/

Printscreeny použité v textu vytvořila redakce Root.cz

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

Autor článku

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