Nauč se Python > Kurzy > Hadí workshop @CodeWeekEU > Had > Úvod do Pygletu

Grafika

Teď si ukážeme, jak napsat grafickou aplikaci.

Python obsahuje nástroje na kreslení obrázků, ale pro tvorbu her nejsou příliš vhodné. Použijeme proto knihovnu (nadstavbu) jménem Pyglet, která je přímo stavěná na interaktivní grafiku.

Musíme si ji ale nejdřív zvlášť nainstalovat. Nejjistější je do příkazové řádky se zapnutým virtuálním prostředím zadat následující dva příkazy. (Existují i jednodušší způsoby, které ovšem vyžadují „správně“ nastavený systém.)

  • Aktualizace nástroje pip, který umí instalovat knihovny pro Python:
    (venv)$ python -m pip install --upgrade pip
    
    (V překladu: Pythone, spusť modul pip a řekni mu, ať nainstaluje a kdyžtak aktualizuje (upgrade) knihovnu pip.)
  • Samotné nainstalování Pygletu:
    (venv)$ python -m pip install pyglet
    
    (V překladu: Pythone, spusť modul pip a řekni mu, ať nainstaluje knihovnu pyglet.)

U mě vypadá instalace nějak takto:

(venv)$ python -m pip install --upgrade pip
Requirement already satisfied: pip in ./venv/lib/python3.6/site-packages (18.0)
(venv)$ python -m pip install pyglet
Collecting pyglet
  Downloading pyglet-1.2.4-py3-none-any.whl (964kB)
Installing collected packages: pyglet
Successfully installed pyglet-1.2.4

Důležité je Successfully installed, resp. Requirement already satisfied na konci. To znamená že je knihovna připravená k použití!

Kostra programu

Teď zkus v editoru vytvořit nový soubor, uložit ho jako grafika.py a napsat do něj následující program:

import pyglet
window = pyglet.window.Window()
pyglet.app.run()
print('Hotovo!')

Spusť ho. Mělo by se objevit černé okýnko.

Okýnko není černé?

Na některých počítačích (často s macOS a některými druhy Linuxu) se stává, že okýnko není černé, ale je v něm nějaký „nepořádek“. To nevadí. Než do okýnka začneme kreslit, nepořádek uklidíme.

AttributeError?

Jestli dostaneš chybu AttributeError: module 'pyglet' has no attribute 'window', zkontroluj si, zě jsi soubor pojmenoval/a grafika.py a ne pyglet.py. Soubor v editoru„ulož jako grafika.py, případný soubor pyglet.py smaž, a zkus to znovu.

Hotovo? Pojďme si vysvětlit, co se v tomhle programu děje.

Příkaz import pyglet ti zpřístupní grafickou knihovnu, tak jako třeba import random ti zpřístupní funkce okolo náhodných čísel.

Zavolání pyglet.window.Window() vytvoří nové okýnko na obrazovce. Vrátí objekt, kterým pak tohle okýnko můžeš ovládat; ten si uložíme do proměnné window.

Zavolání pyglet.app.run() pak spustí aplikaci. Co to znamená?

Jednoduché programy, které jsi zatím psal/a, jsou popisy procesu – podobně jako třeba recepty k vaření. Sled kroků, které Python postupně vykoná od prvního po poslední. Občas se něco opakuje a některé kroky se dají „zabalit“ do funkce, ale vždycky jsme zatím popisovali jeden postup od začátku po konec.

Programy pro složitější aplikace spíš než jako recept vypadají jako příručka automechanika. Popisují, co se má stát v jaké situaci. Třeba program pro textový editor by mohl vypadat takhle:

  • Když uživatel zmáčkne písmenko na klávesnici, přidej ho do dokumentu.
  • Když uživatel zmáčkne ⌫ Backspace, poslední písmenko umaž.

  • Když uživatel zmáčkne tlačítko Uložit, zapiš soubor na disk.

I takový program se dá napsat i jako „recept“ – ale ten recept je pro všechny aplikace stejný:

  • Pořád dokola:
    • Počkej, než se něco zajímavého stane
    • Zareaguj na nastalou situaci

A to je přesně to, co dělá pyglet.app.run(). Zpracovává události, situace na které je potřeba zareagovat. V tvém programu reaguje zavírací tlačítko okýnka a na klávesu Esc tím, že okno zavře a ukončí se.

Tvůj úkol teď bude popsat, jaké další události jsou zajímavé a jak na ně reagovat.

Obsluha událostí

Nejjednodušší událost, kterou můžeme obsloužit, je psaní textu na klávesnici.

Zkus do programu těsně nad řádek pyglet.app.run() dát následující kód:

@window.event
def on_text(text):
    print(text)

Co to je? Je to definice funkce, ale na začátku má dekorátor – tu řádku začínající zavináčem.

Dekorátor window.event je způsob, jak Pygletu říct, že má tuto funkci spustit, když se něco zajímavého stane.

Co zajímavého? To Pyglet zjistí podle jména funkce: on_text reaguje na text. Vždycky, když uživatel zmáčkne klávesu, Pyglet zavolá tvoji funkci!

A co udělá tvoje funkce? Zavolá print. To už znáš. Zadaný text se vypíše na konzoli, ze které program spouštíš. To, že je otevřené okýnko, neznamená že print začne automaticky psát do něj!

Kreslení

Jak psát do okýnka? To je trochu složitější než do konzole. Text tu může mít různé barvy, velikosti, druhy písma, může být všelijak posunutý nebo natočený…

Všechny tyhle atributy písma můžeme (i se samotným textem) uložit do objektu Label („popisek“). Zkus to – dej následující kód pod řádek s window =:

label = pyglet.text.Label("Ahoj!", x=10, y=20)

V proměnné label teď budeš mít máš popisek s textem "Ahoj", který patří na pozici (10, 20) – 10 bodů od pravého okraje okna, 20 od spodního.

To je ale jen informace. Podobně jako pro vypsání textu do konzole je potřeba zavolat print, pro nakreslení textu je potřeba reagovat na událost vykreslení oknaon_draw.

Dej pod funkci on_text tento kód:

@window.event
def on_draw():
    window.clear()
    label.draw()

Tuhle funkci Pyglet zavolá vždycky, když je potřeba nakreslit obsah okýnka. U animací (filmů nebo her) to často bývá třeba 60× za sekundu („60 FPS“).

Funkce dělá dvě věci:

  • Smaže celé okýnko (nabarví ho na černo)
  • Vykreslí text

V okně teď bude vidět pozdrav!

Zkus ještě změnit on_text tak, aby se zadaný text místo na konzoli ukázal v okýnku. To se dělá přiřazením do atributu label.text:

@window.event
def on_text(text):
    print('Starý text:', label.text)
    label.text = text
    print('Nový text:', label.text)

Zvládneš v této funkci nový text přidat ke starému, aby program fungoval jako jednoduchý textový editor?

Řešení

Další událostí

Na jaké další události se dá reagovat? Všechny jsou popsané v dokumentaci Pygletu. Tady uvádím pár zajímavých.

Stisk klávesy

Klávesy, které nezadávají text (šipky, Backspace nebo Enter, atp.) se dají rozpoznat v události on_key_press.

Funkce on_key_press má dva argumenty: první je kód klávesy, který můžeš porovnat s konstantou z pyglet.window.key. Druhý určuje stisknuté modifikátory jako Shift nebo Ctrl.

@window.event
def on_key_press(key_code, modifier):
    if key_code == pyglet.window.key.BACKSPACE:
        label.text = label.text[:-1]

    if key_code == pyglet.window.key.ENTER:
        print('Zadaná zpráva:', label.text)
        window.close()

Na macOS budeš možná muset zaměňit BACKSPACE za DELETE. (Nebo si doma nastuduj způsob, jak to dělat automaticky a správně.)

Kliknutí myši

Při obsluze události on_mouse_press dostaneš informace o pozici kliknutí (x-ovou a x-ovou souřadnici) a navíc informaci o stisknutém tlačítku myši a modifikátoru.

Takhle se třeba popisek přesune na místo kliknutí:

@window.event
def on_mouse_press(x, y, button, modifier):
    label.x = x
    label.y = y

Celý program

Pro případ, že by ses ztratil/a nebo nevěděla, kam který kousek kódu patří, uvádím výsledný ukázkový program.

import pyglet
window = pyglet.window.Window()
label = pyglet.text.Label("Ahoj!", x=10, y=20)


@window.event
def on_draw():
    window.clear()
    label.draw()


@window.event
def on_text(text):
    label.text = label.text + text


@window.event
def on_key_press(key_code, modifier):
    if key_code == pyglet.window.key.BACKSPACE:
        label.text = label.text[:-1]

    if key_code == pyglet.window.key.ENTER:
        print('Zadaná zpráva:', label.text)
        window.close()


@window.event
def on_mouse_press(x, y, button, modifier):
    label.x = x
    label.y = y


pyglet.app.run()

Toto je stránka lekce z kurzu, který probíhá nebo proběhl naživo s instruktorem.