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 pojmenovala 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 psala, 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 ztratila 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()
{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2018/snake-brno:workshop:1",
      "title": "Úvod do Pygletu",
      "html": "\n          \n    \n\n    <h1>Grafika</h1>\n<p>Te&#x10F; si uk&#xE1;&#x17E;eme, jak napsat grafickou aplikaci.</p>\n<p>Python obsahuje n&#xE1;stroje na kreslen&#xED; obr&#xE1;zk&#x16F;,\nale pro tvorbu her nejsou p&#x159;&#xED;li&#x161; vhodn&#xE9;.\nPou&#x17E;ijeme proto <em>knihovnu</em> (nadstavbu) jm&#xE9;nem Pyglet, kter&#xE1; je p&#x159;&#xED;mo stav&#x11B;n&#xE1;\nna interaktivn&#xED; grafiku.</p>\n<p>Mus&#xED;me si ji ale nejd&#x159;&#xED;v zvl&#xE1;&#x161;&#x165; nainstalovat.\nNejjist&#x11B;j&#x161;&#xED; je do p&#x159;&#xED;kazov&#xE9; &#x159;&#xE1;dky se zapnut&#xFD;m virtu&#xE1;ln&#xED;m prost&#x159;ed&#xED;m\nzadat n&#xE1;sleduj&#xED;c&#xED; dva p&#x159;&#xED;kazy.\n(Existuj&#xED; i jednodu&#x161;&#x161;&#xED; zp&#x16F;soby, kter&#xE9; ov&#x161;em vy&#x17E;aduj&#xED; &#x201E;spr&#xE1;vn&#x11B;&#x201C;\nnastaven&#xFD; syst&#xE9;m.)</p>\n<ul>\n<li>Aktualizace n&#xE1;stroje <code>pip</code>, kter&#xFD; um&#xED; instalovat knihovny pro Python:<div class=\"highlight\"><pre><span></span><span class=\"gp\">(venv)$ </span>python -m pip install --upgrade pip\n</pre></div>(V&#xA0;p&#x159;ekladu: <strong>Python</strong>e, spus&#x165; <strong>m</strong>odul <strong>pip</strong> a &#x159;ekni mu,\na&#x165; na<strong>instal</strong>uje a kdy&#x17E;tak aktualizuje (<em>upgrade</em>) knihovnu <strong>pip</strong>.)</li>\n<li>Samotn&#xE9; nainstalov&#xE1;n&#xED; Pygletu:<div class=\"highlight\"><pre><span></span><span class=\"gp\">(venv)$ </span>python -m pip install pyglet\n</pre></div>(V&#xA0;p&#x159;ekladu: <strong>Python</strong>e, spus&#x165; <strong>m</strong>odul <strong>pip</strong> a &#x159;ekni mu,\na&#x165; na<strong>instal</strong>uje knihovnu <strong>pyglet</strong>.)</li>\n</ul>\n<p>U m&#x11B; vypad&#xE1; instalace n&#x11B;jak takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">(venv)$ </span>python -m pip install --upgrade pip\n<span class=\"go\">Requirement already satisfied: pip in ./venv/lib/python3.6/site-packages (18.0)</span>\n<span class=\"gp\">(venv)$ </span>python -m pip install pyglet\n<span class=\"go\">Collecting pyglet</span>\n<span class=\"go\">  Downloading pyglet-1.2.4-py3-none-any.whl (964kB)</span>\n<span class=\"go\">Installing collected packages: pyglet</span>\n<span class=\"go\">Successfully installed pyglet-1.2.4</span>\n</pre></div><p>D&#x16F;le&#x17E;it&#xE9; je <code>Successfully installed</code>, resp. <code>Requirement already satisfied</code>\nna konci.\nTo znamen&#xE1; &#x17E;e je knihovna p&#x159;ipraven&#xE1; k&#xA0;pou&#x17E;it&#xED;!</p>\n<h2>Kostra programu</h2>\n<p>Te&#x10F; zkus v&#xA0;editoru vytvo&#x159;it nov&#xFD; soubor, ulo&#x17E;it ho jako <code>grafika.py</code>\na napsat do n&#x11B;j n&#xE1;sleduj&#xED;c&#xED; program:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">pyglet</span>\n<span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">Window</span><span class=\"p\">()</span>\n<span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">app</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Hotovo!&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Spus&#x165; ho. M&#x11B;lo by se objevit &#x10D;ern&#xE9; ok&#xFD;nko.</p>\n<div class=\"admonition note\"><p class=\"admonition-title\">Ok&#xFD;nko nen&#xED; &#x10D;ern&#xE9;?</p>\n<p>Na n&#x11B;kter&#xFD;ch po&#x10D;&#xED;ta&#x10D;&#xED;ch (&#x10D;asto s&#xA0;macOS a n&#x11B;kter&#xFD;mi druhy Linuxu) se st&#xE1;v&#xE1;,\n&#x17E;e ok&#xFD;nko nen&#xED; &#x10D;ern&#xE9;, ale je v n&#x11B;m n&#x11B;jak&#xFD; &#x201E;nepo&#x159;&#xE1;dek&#x201C;.\nTo nevad&#xED;.\nNe&#x17E; do ok&#xFD;nka za&#x10D;neme kreslit, nepo&#x159;&#xE1;dek uklid&#xED;me.</p>\n</div><div class=\"admonition note\"><p class=\"admonition-title\">AttributeError?</p>\n<p>Jestli dostane&#x161; chybu\n<code>AttributeError: module &apos;pyglet&apos; has no attribute &apos;window&apos;</code>, zkontroluj si,\nz&#x11B; jsi soubor pojmenovala <code>grafika.py</code> a ne <code>pyglet.py</code>.\nSoubor v&#xA0;editoru&#x201E;ulo&#x17E; jako <code>grafika.py</code>, p&#x159;&#xED;padn&#xFD; soubor <code>pyglet.py</code> sma&#x17E;,\na zkus to znovu.</p>\n</div><p>Hotovo? Poj&#x10F;me si vysv&#x11B;tlit, co se v tomhle programu d&#x11B;je.</p>\n<p>P&#x159;&#xED;kaz <code>import pyglet</code> ti zp&#x159;&#xED;stupn&#xED; grafickou knihovnu, tak jako t&#x159;eba\n<code>import random</code> ti zp&#x159;&#xED;stupn&#xED; funkce okolo n&#xE1;hodn&#xFD;ch &#x10D;&#xED;sel.</p>\n<p>Zavol&#xE1;n&#xED; <code>pyglet.window.Window()</code> vytvo&#x159;&#xED; nov&#xE9; <em>ok&#xFD;nko</em> na obrazovce.\nVr&#xE1;t&#xED; objekt, kter&#xFD;m pak tohle ok&#xFD;nko m&#x16F;&#x17E;e&#x161; ovl&#xE1;dat; ten si ulo&#x17E;&#xED;me\ndo prom&#x11B;nn&#xE9; <code>window</code>.</p>\n<p>Zavol&#xE1;n&#xED; <code>pyglet.app.run()</code> pak spust&#xED; aplikaci.\nCo to znamen&#xE1;?</p>\n<p>Jednoduch&#xE9; programy, kter&#xE9; jsi zat&#xED;m psala, jsou popisy procesu &#x2013; podobn&#x11B;\njako t&#x159;eba recepty k&#xA0;va&#x159;en&#xED;.\nSled krok&#x16F;, kter&#xE9; Python postupn&#x11B; vykon&#xE1; od prvn&#xED;ho po posledn&#xED;.\nOb&#x10D;as se n&#x11B;co opakuje a n&#x11B;kter&#xE9; kroky se daj&#xED; &#x201E;zabalit&#x201C; do funkce,\nale v&#x17E;dycky jsme zat&#xED;m popisovali jeden postup od za&#x10D;&#xE1;tku po konec.</p>\n<p>Programy pro slo&#x17E;it&#x11B;j&#x161;&#xED; aplikace sp&#xED;&#x161; ne&#x17E; jako recept vypadaj&#xED; jako p&#x159;&#xED;ru&#x10D;ka\nautomechanika.\nPopisuj&#xED;, co se m&#xE1; st&#xE1;t v&#xA0;jak&#xE9; situaci.\nT&#x159;eba program pro textov&#xFD; editor by mohl vypadat takhle:</p>\n<ul>\n<li>Kdy&#x17E; u&#x17E;ivatel zm&#xE1;&#x10D;kne p&#xED;smenko na kl&#xE1;vesnici, p&#x159;idej ho do dokumentu.</li>\n<li><p>Kdy&#x17E; u&#x17E;ivatel zm&#xE1;&#x10D;kne <kbd>&#x232B; Backspace</kbd>, posledn&#xED; p&#xED;smenko uma&#x17E;.</p></li>\n<li>Kdy&#x17E; u&#x17E;ivatel zm&#xE1;&#x10D;kne tla&#x10D;&#xED;tko Ulo&#x17E;it, zapi&#x161; soubor na disk.</li>\n</ul>\n<p>I takov&#xFD; program se d&#xE1; napsat i jako &#x201E;recept&#x201C; &#x2013; ale ten recept je pro v&#x161;echny\naplikace stejn&#xFD;:</p>\n<ul>\n<li>Po&#x159;&#xE1;d dokola:<ul>\n<li>Po&#x10D;kej, ne&#x17E; se n&#x11B;co zaj&#xED;mav&#xE9;ho stane</li>\n<li>Zareaguj na nastalou situaci</li>\n</ul>\n</li>\n</ul>\n<p>A to je p&#x159;esn&#x11B; to, co d&#x11B;l&#xE1; <code>pyglet.app.run()</code>.\nZpracov&#xE1;v&#xE1; <em>ud&#xE1;losti</em>, situace na kter&#xE9; je pot&#x159;eba zareagovat.\nV&#xA0;tv&#xE9;m programu reaguje zav&#xED;rac&#xED; tla&#x10D;&#xED;tko ok&#xFD;nka a na kl&#xE1;vesu <kbd>Esc</kbd>\nt&#xED;m, &#x17E;e okno zav&#x159;e a ukon&#x10D;&#xED; se.</p>\n<p>Tv&#x16F;j &#xFA;kol te&#x10F; bude popsat, jak&#xE9; dal&#x161;&#xED; ud&#xE1;losti jsou zaj&#xED;mav&#xE9;\na jak na n&#x11B; reagovat.</p>\n<h2>Obsluha ud&#xE1;lost&#xED;</h2>\n<p>Nejjednodu&#x161;&#x161;&#xED; ud&#xE1;lost, kterou m&#x16F;&#x17E;eme obslou&#x17E;it, je psan&#xED; textu na kl&#xE1;vesnici.</p>\n<p>Zkus do programu t&#x11B;sn&#x11B; nad &#x159;&#xE1;dek <code>pyglet.app.run()</code> d&#xE1;t n&#xE1;sleduj&#xED;c&#xED; k&#xF3;d:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_text</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</pre></div><p>Co to je?\nJe to definice funkce, ale na za&#x10D;&#xE1;tku m&#xE1; <em>dekor&#xE1;tor</em> &#x2013; tu &#x159;&#xE1;dku za&#x10D;&#xED;naj&#xED;c&#xED;\nzavin&#xE1;&#x10D;em.</p>\n<p>Dekor&#xE1;tor <code>window.event</code> je zp&#x16F;sob, jak Pygletu &#x159;&#xED;ct, &#x17E;e m&#xE1; tuto funkci\nspustit, kdy&#x17E; se n&#x11B;co zaj&#xED;mav&#xE9;ho stane.</p>\n<p>Co zaj&#xED;mav&#xE9;ho?\nTo Pyglet zjist&#xED; podle jm&#xE9;na funkce: <code>on_text</code> reaguje na text.\nV&#x17E;dycky, kdy&#x17E; u&#x17E;ivatel zm&#xE1;&#x10D;kne kl&#xE1;vesu, Pyglet zavol&#xE1; tvoji funkci!</p>\n<p>A co ud&#x11B;l&#xE1; tvoje funkce? Zavol&#xE1; <code>print</code>. To u&#x17E; zn&#xE1;&#x161;.\nZadan&#xFD; text se vyp&#xED;&#x161;e na konzoli, ze kter&#xE9; program spou&#x161;t&#xED;&#x161;.\nTo, &#x17E;e je otev&#x159;en&#xE9; ok&#xFD;nko, neznamen&#xE1; &#x17E;e <code>print</code> za&#x10D;ne automaticky ps&#xE1;t do n&#x11B;j!</p>\n<h2>Kreslen&#xED;</h2>\n<p>Jak ps&#xE1;t do ok&#xFD;nka?\nTo je trochu slo&#x17E;it&#x11B;j&#x161;&#xED; ne&#x17E; do konzole.\nText tu m&#x16F;&#x17E;e m&#xED;t r&#x16F;zn&#xE9; barvy, velikosti, druhy p&#xED;sma,\nm&#x16F;&#x17E;e b&#xFD;t v&#x161;elijak posunut&#xFD; nebo nato&#x10D;en&#xFD;&#x2026;</p>\n<p>V&#x161;echny tyhle <em>atributy</em> p&#xED;sma m&#x16F;&#x17E;eme (i se samotn&#xFD;m textem) ulo&#x17E;it do objektu \n<code>Label</code> (&#x201E;popisek&#x201C;).\nZkus to &#x2013; dej n&#xE1;sleduj&#xED;c&#xED; k&#xF3;d pod &#x159;&#xE1;dek s&#xA0;<code>window =</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">Label</span><span class=\"p\">(</span><span class=\"s2\">&quot;Ahoj!&quot;</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"mi\">20</span><span class=\"p\">)</span>\n</pre></div><p>V&#xA0;prom&#x11B;nn&#xE9; <code>label</code> te&#x10F; bude&#x161; m&#xED;t m&#xE1;&#x161; popisek s&#xA0;textem <code>&quot;Ahoj&quot;</code>, kter&#xFD; pat&#x159;&#xED;\nna pozici (10, 20) &#x2013; 10 bod&#x16F; od prav&#xE9;ho okraje okna, 20 od spodn&#xED;ho.</p>\n<p>To je ale jen informace.\nPodobn&#x11B; jako pro vyps&#xE1;n&#xED; textu do konzole je pot&#x159;eba zavolat <code>print</code>,\npro nakreslen&#xED; textu je pot&#x159;eba reagovat na ud&#xE1;lost\n<em>vykreslen&#xED; okna</em> &#x2013; <code>on_draw</code>.</p>\n<p>Dej pod funkci <code>on_text</code> tento k&#xF3;d:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_draw</span><span class=\"p\">():</span>\n    <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">draw</span><span class=\"p\">()</span>\n</pre></div><p>Tuhle funkci Pyglet zavol&#xE1; v&#x17E;dycky, kdy&#x17E; je pot&#x159;eba nakreslit obsah ok&#xFD;nka.\nU animac&#xED; (film&#x16F; nebo her) to &#x10D;asto b&#xFD;v&#xE1; t&#x159;eba 60&#xD7; za sekundu\n(&#x201E;<a href=\"https://cs.wikipedia.org/wiki/Sn%C3%ADmkov%C3%A1_frekvence\">60 FPS</a>&#x201C;).</p>\n<p>Funkce d&#x11B;l&#xE1; dv&#x11B; v&#x11B;ci:</p>\n<ul>\n<li>Sma&#x17E;e cel&#xE9; ok&#xFD;nko (nabarv&#xED; ho na &#x10D;erno)</li>\n<li>Vykresl&#xED; text</li>\n</ul>\n<p>V&#xA0;okn&#x11B; te&#x10F; bude vid&#x11B;t pozdrav!</p>\n<p>Zkus je&#x161;t&#x11B; zm&#x11B;nit <code>on_text</code> tak, aby se zadan&#xFD; text m&#xED;sto na konzoli\nuk&#xE1;zal v ok&#xFD;nku.\nTo se d&#x11B;l&#xE1; p&#x159;i&#x159;azen&#xED;m do <em>atributu</em> <code>label.text</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_text</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Star&#xFD; text:&apos;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Nov&#xFD; text:&apos;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</pre></div><p>Zvl&#xE1;dne&#x161; v t&#xE9;to funkci nov&#xFD; text p&#x159;idat ke star&#xE9;mu,\naby program fungoval jako jednoduch&#xFD; textov&#xFD; editor?</p>\n<div class=\"solution\" id=\"solution-0\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-brno/fast-track/pyglet/index/solutions/0/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_text</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span> <span class=\"o\">+</span> <span class=\"n\">text</span>\n</pre></div>\n    </div>\n</div><h2>Dal&#x161;&#xED; ud&#xE1;lost&#xED;</h2>\n<p>Na jak&#xE9; dal&#x161;&#xED; ud&#xE1;losti se d&#xE1; reagovat?\nV&#x161;echny jsou popsan&#xE9; v&#xA0;<a href=\"https://pyglet.readthedocs.io/en/latest/modules/window.html#pyglet.window.Window.on_activate\">dokumentaci Pygletu</a>.\nTady uv&#xE1;d&#xED;m p&#xE1;r zaj&#xED;mav&#xFD;ch.</p>\n<h3>Stisk kl&#xE1;vesy</h3>\n<p>Kl&#xE1;vesy, kter&#xE9; nezad&#xE1;vaj&#xED; text (&#x161;ipky, <kbd>Backspace</kbd> nebo\n<kbd>Enter</kbd>, atp.) se daj&#xED; rozpoznat v ud&#xE1;losti <code>on_key_press</code>.</p>\n<p>Funkce <code>on_key_press</code> m&#xE1; dva argumenty: prvn&#xED; je k&#xF3;d kl&#xE1;vesy,\nkter&#xFD; m&#x16F;&#x17E;e&#x161; porovnat s&#xA0;konstantou z&#xA0;<a href=\"https://pyglet.readthedocs.io/en/latest/modules/window_key.html#key-constants\">pyglet.window.key</a>.\nDruh&#xFD; ur&#x10D;uje stisknut&#xE9; modifik&#xE1;tory jako <kbd>Shift</kbd> nebo <kbd>Ctrl</kbd>.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_key_press</span><span class=\"p\">(</span><span class=\"n\">key_code</span><span class=\"p\">,</span> <span class=\"n\">modifier</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">key_code</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">BACKSPACE</span><span class=\"p\">:</span>\n        <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">key_code</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">ENTER</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Zadan&#xE1; zpr&#xE1;va:&apos;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n        <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</pre></div><p>Na macOS bude&#x161; mo&#x17E;n&#xE1; muset zam&#x11B;&#x148;it <code>BACKSPACE</code> za <code>DELETE</code>. \n(Nebo si doma nastuduj <a href=\"https://pyglet.readthedocs.io/en/latest/programming_guide/keyboard.html#motion-events\">zp&#x16F;sob</a>, jak to d&#x11B;lat automaticky a spr&#xE1;vn&#x11B;.)</p>\n<h3>Kliknut&#xED; my&#x161;i</h3>\n<p>P&#x159;i obsluze ud&#xE1;losti <code>on_mouse_press</code> dostane&#x161; informace o pozici\nkliknut&#xED; (<var>x</var>-ovou a <var>x</var>-ovou sou&#x159;adnici)\na nav&#xED;c informaci o stisknut&#xE9;m tla&#x10D;&#xED;tku my&#x161;i a modifik&#xE1;toru.</p>\n<p>Takhle se t&#x159;eba popisek p&#x159;esune na m&#xED;sto kliknut&#xED;:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_mouse_press</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">button</span><span class=\"p\">,</span> <span class=\"n\">modifier</span><span class=\"p\">):</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">x</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">y</span>\n</pre></div><h2>Cel&#xFD; program</h2>\n<p>Pro p&#x159;&#xED;pad, &#x17E;e by ses ztratila nebo nev&#x11B;d&#x11B;la,\nkam kter&#xFD; kousek k&#xF3;du pat&#x159;&#xED;, uv&#xE1;d&#xED;m v&#xFD;sledn&#xFD; uk&#xE1;zkov&#xFD; program.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">pyglet</span>\n<span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">Window</span><span class=\"p\">()</span>\n<span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">Label</span><span class=\"p\">(</span><span class=\"s2\">&quot;Ahoj!&quot;</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"mi\">20</span><span class=\"p\">)</span>\n\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_draw</span><span class=\"p\">():</span>\n    <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">draw</span><span class=\"p\">()</span>\n\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_text</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span> <span class=\"o\">+</span> <span class=\"n\">text</span>\n\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_key_press</span><span class=\"p\">(</span><span class=\"n\">key_code</span><span class=\"p\">,</span> <span class=\"n\">modifier</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">key_code</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">BACKSPACE</span><span class=\"p\">:</span>\n        <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">key_code</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">ENTER</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Zadan&#xE1; zpr&#xE1;va:&apos;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n        <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_mouse_press</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">button</span><span class=\"p\">,</span> <span class=\"n\">modifier</span><span class=\"p\">):</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">x</span>\n    <span class=\"n\">label</span><span class=\"o\">.</span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">y</span>\n\n\n<span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">app</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</pre></div>\n\n\n        "
    }
  }
}