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í.
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()
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)
Co tento program udělá, když obrátíme pořadí create_oval a delete?
Na které souřadnici bude nakreslen poslední obrazec?
Co udělá tento program, pokud nahradíme podmínku touto y == 200?
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?
Vytvořte program 14_vodorovne.py, který přesune kuličku vodorovně od levého okraje k pravému okraji.
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ů.
Vytvořte program 14_sikmo.py, ve kterém se bude kulička pohybovat šikmo dolů.
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)
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)
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:
Vytvořte program 14_kolize.py, který má následující vlastnosti:
Vytvořte program 14_dostihy.py simulující dostihový závod, který má následující vlastnosti: