Lekce 14: Časovač

python.edumach.cz



1. Úvod

V předchozí kapitole jsme v místě kliknutí nakreslili barevné kroužky podle určité podmínky. Abychom nakreslili více kroužků, museli jsme kliknout myší vícekrát. To můžeme prozatím vyřešit pomocí cyklu for: nakreslíme více kroužků najednou na náhodném místě.

# 14_1.py

import tkinter
import random

canvas = tkinter.Canvas()
canvas.pack()

def krouzek():
    x = random.randrange(450)
    y = random.randrange(320)
    if 100<x<150 or 50<y<100:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='green')
    else:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='yellow')

for i in range(1, 1000):
    krouzek()

Cyklus for již můžeme upravit tak, aby se jednotlivé iterace prováděly postupně s určitým časovým zpožděním. K tomu jsme použili canvas.after() a canvas.update(). Takto upravíme smyčku for, aby se vykreslovala postupně.

for i in range(1, 1000):
    krouzek()
    canvas.update()
    canvas.after(10)

Cyklus for používáme v situacích, kdy předem víme počet opakování. Proto se jí říká cyklus s pevným počtem opakování.

2. Časovač

Existují však situace, kdy potřebujeme akci opakovat, ale přesný počet opakování předem neznáme. K řešení takového problému můžeme použít tzv. časovač, který v pravidelných časových intervalech opakuje zadanou posloupnost příkazů. K tomu slouží příkaz

canvas.after(time, function)

Zadáme mu nejen čas v milisekundách, ale také název funkce, která se má provést.

Náš program po úpravě pomocí časovače:

# 14_2.py

import tkinter
import random

canvas = tkinter.Canvas(width=450,height=320)
canvas.pack()

def krouzek():
    x = random.randrange(450)
    y = random.randrange(320)
    if 100<x<150 or 50<y<100:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='green')
    else:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='yellow')
    canvas.after(10, krouzek)

def ctverec():
    x = random.randrange(450)
    y = random.randrange(320)
    if 100<x<150 or 50<y<100:
        canvas.create_rectangle(x-5, y-5, x+5, y+5, fill='red')
    else:
        canvas.create_rectangle(x-5, y-5, x+5, y+5, fill='blue')
    canvas.after(30, ctverec)

ctverec()
krouzek()

Program po nějaké době vykreslí takový obrázek:


Následující program postupně nakreslí několik kuliček.

# 14_3.py

import tkinter

canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()

def micek():
    global x
    global y
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y + 5
    if y < 200:
        canvas.after(100, micek)
	
x = 200
y = 5

micek()

3. Globální proměnná

Všimněte si, že jsme v předchozím programu nastavili proměnnou x na 200 a y na 5. V těchto proměnných jsou souřadnice, na kterých je nakreslena první kulička. Po nastavení proměnných spustíme funkci micek. Tato funkce nakreslí kuličku (kruh) na souřadnice podle hodnot proměnných x a y. Další kuličku chceme nakreslit na souřadnice, které jsou uvedeny v proměnných x a y. Další chceme nakreslit o 5 bodů níže. Proto zvýšíme y o 5, takže napíšeme y = y + 5. Protože jsme ve funkci micek, nemůžeme zde normálně měnit hodnotu proměnné, která se používá v hlavním programu mimo naši funkci. Jak y, tak x jsou globální proměnné, nikoli lokální proměnné ve funkci, kde je chceme změnit. V takových situaci musíme použít příkaz global a název proměnné, abychom funkci sdělili, že chceme pracovat s proměnnou, která je mimi tělo funkce. Nyní má y hodnotu 10. V dalším řádku se ptáme, zda je y menší než 200, a to pouze v případě, že je tato podmínka splněna, naplánujeme další provedení funkce micek na 100 milisekund. Vidíme, že jsme vytvořili časovač, který neopakuje příkazy donekonečna, ale jen tak dlouho, dokud je splněna podmínka. Po spuštění programu uvidíme, že se pod sebou vykresluje několik kuliček.


Pomocí canvas.delete('all') můžeme odstranit vše, co jsme nakreslili. Pokud tento příkaz napíšeme na začátku funkce, funkce pokaždé vymaže vše nakreslené a my uvidíme pouze poslední nakreslený objekt. To je princip animace. Nejprve vymažeme původní obrázky a nakreslíme stejný tvar v posunuté poloze. A tak stále dokola.

def micek():
    global x
    global y
    canvas.delete('all')
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y + 5
    if y < 200:
        canvas.after(100, micek)

3.1. ❓ Otázky

  1. Co tento program udělá, když obrátíme pořadí create_oval a delete?

  2. Na které souřadnici bude nakreslen poslední obrazec?

  3. Co udělá tento program, pokud nahradíme podmínku touto y == 200?

  4. Co program udělá, jestliže zvětšíme y o 6 (y = y + 6) a nahradíme podmínku následující: y == 200?

4. 💾 Cvičení

4.1. Kulička vodorovně vpravo

Vytvořte program 14_vodorovne.py, který přesune kuličku vodorovně od levého okraje k pravému okraji.

4.2. Kulička svisle dolů

Vytvořte program 14_svisle.py, ve kterém bude kulička padat svisle shora dolů, a až dosáhne spodní hrany, bude opět padat shora dolů.

4.3. Kulička šikmo dolů

Vytvořte program 14_sikmo.py, ve kterém se bude kulička pohybovat šikmo dolů.

5. Co program dělá (1)

Zjistěte, co udělá následující program:

# 14_4.py

import tkinter

canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()

def micek():
    global x
    global y
    global pokracovat
    canvas.delete('all')
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y + 5
    if y > 250:
        y = 5
    if pokracovat == 1:
        canvas.after(100, micek)

def stop(souradnice):
    global pokracovat
    pokracovat = 0
	
pokracovat = 1
x = 200
y = 5
micek()

canvas.bind('<ButtonPress-1>', stop)

6. Co program dělá (2)

Zjistěte, co udělá následující program:

# 14_5.py

import tkinter

canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()

def micek():
    # úspornější zápis pro více proměnných
    global x, y, pokracovat
    canvas.delete('all')
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y + 5
    if y > 250:
        y = 5
    if pokracovat == 1:
        canvas.after(100, micek)

def stop(souradnice):
    global pokracovat
    if pokracovat == 1:
        pokracovat = 0
    else:
        pokracovat = 1
        micek()

pokracovat = 1
x = 200
y = 5
micek()
canvas.bind('<ButtonPress-1>', stop)

6.1. Jedničky a nuly

Vytvořte program 14_jednicky_nuly.py, který bude postupně zapisovat na plátno 0 nebo 1 (náhodně vybrané):

Program bude mít následující vlastnosti:

6.2. Kolize

Vytvořte program 14_kolize.py, který má následující vlastnosti:

6.3. Dostihy

Vytvořte program 14_dostihy.py simulující dostihový závod, který má následující vlastnosti: