Späť na hlavnú stránku

Udalosti, interaktívne aplikácie

Interaktívne aplikácie v Tkinter umožňujú používateľovi komunikovať s objektmi na plátne pomocou myši a klávesnice. Naučíme sa pohybovať objektami, reagovať na kliknutia myšou a spracovávať vstup z klávesnice. Tieto techniky sú základom pre tvorbu jednoduchých hier a interaktívnych aplikácií.

Pohyb objektov po plátne

Pre pohyb objektov tu používame metódy move() a coords(). Metóda move() posúva objekt o zadané hodnoty, zatiaľ čo coords() nastaví absolútne súradnice objektu.

Základné metódy pre pohyb objektov na plátne:

move(objekt, dx, dy) - posunie objekt o dx, dy pixelov
coords(objekt, x1, y1, x2, y2, ...) - nastaví nové súradnice objektu
itemconfig(objekt, parameter=hodnota) - zmení vlastnosti objektu tak, že mu nastaví novú hodnotu parametra

Program postupne vykonáva všetky príkazy v programe, robí to však rýchlo, ľudské oko nestihne zaznamenať zmeny, preto je potrebné pozdržať program (na niekoľko milisekúnd), a nanovo vykresliť obsah plátna. Na to slúži dvojica príkazov:
platno.after(milisekund)
platno.update()

import tkinter
platno=tkinter.Canvas(bg="white", height=400, width=500)
platno.pack()

#vykreslenie gulky na plátne
gulka = platno.create_oval(200,150,210,160, fill="yellow")
platno.after(500)
platno.update()

#gulka sa posunie o 10 doprava
platno.move(gulka, 10, 0)
platno.after(1000)
platno.update()

#gulka zmení polohu
platno.coords(gulka, 100, 100, 150, 150)
platno.after(2000)
platno.update()

#gulka zmení farbu
platno.itemconfig(gulka, fill="red")

Simulátor akvária s rybkami

import tkinter,random

# Vytvorenie okna a plátna
okno = tkinter.Tk()
okno.title("Akvárium s rybkami")
platno = tkinter.Canvas(okno, width=600, height=400, bg="lightblue")
platno.pack()

# Vytvorenie rybičiek - zoznam s [objekt, rychlost_x, rychlost_y]
rybicky = []
farby = ["red", "orange", "yellow", "green", "blue", "purple"]
for i in range(5):
    x = random.randint(30, 570)
    y = random.randint(30, 370)
    farba = random.choice(farby)
    # Vytvorenie rybičky (jednoduchý ovál)
    rybka = platno.create_oval(x-15, y-8, x+15, y+8, fill=farba)
    # Náhodná rýchlosť
    vx = random.randint(-3, 3)
    vy = random.randint(-3, 3)
    # Pridanie do zoznamu
    rybicky.append([rybka, vx, vy])

def pohyb_rybiciek():
    for i in range(len(rybicky)):
        rybka = rybicky[i][0]
        vx = rybicky[i][1]
        vy = rybicky[i][2]
        # Získanie pozície
        x1, y1, x2, y2 = platno.coords(rybka)
        # Kontrola hraníc a zmena smeru
        if x2 >= 600 or x1 < = 0:
            rybicky[i][1] = -vx
            # zmena smeru x
        if y2 >= 400 or y1 <= 0:
            rybicky[i][2] = -vy
            # zmena smeru y
        # Pohyb rybky
        platno.move(rybka, rybicky[i][1], rybicky[i][2])
        # Opakovanie
        okno.after(50, pohyb_rybiciek)
        # Spustenie animácie
        pohyb_rybiciek()
okno.mainloop()

Reakcia na udalosti od myšky

Pomocou metódy .bind() na plátne (knižnica tkinter) vieme spracovať rôzne udalosti od myšky. Postupne obslúžime tri udalosti: kliknutie (zatlačenie tlačidla myši) t.j. <ButtonPress>', ťahanie (posúvanie myšou so zatlačeným tlačidlom alebo bez zatlačeného tlačidla) t.j. '<Motion>' a pustenie tlačidla myši t.j. '<ButtonRelease>'.

Klikanie myškou

Po spustení programu sa zakaždým, keď užívateľ klikne na plátno vyvolá nejaká obslužná funkcia. V metóde .bind() je prvým parametrom názov udalosti a druhým parametrom určíme, ktorá funkcia sa má po danej udalosti vykonať. Pri definovaní obslužnej funkcie musíme vo funkcii stanoviť vždy jeden povinný parameter (napr. event), v ktorom sa uchovajú dôležité hodnoty pri udalosti (napríklad súradnice polohy myši event.x, event.y).

Program, v ktorom sa vykreslí na mieste kliknutia myšou krížik:

import tkinter
platno = tkinter.Canvas()
platno.pack()

def klikol(event):
     surX = event.x
     surY = event.y
     platno.create_text(surX,surY,text="x")

platno.bind('<ButtonPress>', klikol)

Pozn. klikať sa dá rôznymi tlačidlami myši (ľavé, stredné koliesko, pravé).

'<ButtonPress>' ... stlačenie ľubovoľného tlačidla myši
'<Button-1>' ... stlačenie ľavého tlačidla myši
'<Button-2>' ... stlačenie stredného tlačidla myši
'<Button-3>' ... stlačenie pravého tlačidla myši
'<Double-Button-1>' ... dvojklik ľavého tlačidla myši
'<Double-Button-2>' ... dvojklik stredného kolieska myši
'<Double-Button-3>' ... dvojklik pravého tlačidla myši

Ťahanie myškou

Pri ťahaní myšou so stlačeným niektorým tlačidlom, alebo aj pri ťahaní myšou bez tlačidla sa môže vyvolať nejaká obslužná funkcia.

Napríklad nižšie je program, v ktorom sa vykresľujú červené krúžky pri ťahaní myšou.

import tkinter
platno = tkinter.Canvas()
platno.pack()

def kresli(event):
     surX = event.x
     surY = event.y
     platno.create_oval(surX-5,surY-5,surX+5,surY+5,fill="red")

platno.bind('<Motion>', kresli)
'<Motion>' ... ťahanie myškou bez stlačeného tlačidla myši
'<B1-Motion>' ... ťahanie myškou pri stlačenom ľavom tlačidle myši
'<B2-Motion>' ... ťahanie myškou pri stlačenom strednom koliesku myši
'<B3-Motion>' ... ťahanie myškou pri stlačenom pravom tlačidle myši

Pustenie tlačidla myšky

Pri uvoľnení stlačeného tlačidla myši sa dá vyvolať nejaká obslužná funkcia.

Program, v ktorom sa vykreslí na mieste pozície myši malý biely krúžok v momente pustenia (uvolnenia tlačidla myši):

import tkinter
platno = tkinter.Canvas()
platno.pack()

def kresli(event):
     surX = event.x
     surY = event.y
     platno.create_oval(surX-5,surY-5,surX+5,surY+5,fill="red")

def pusti(event):
     surX = event.x
     surY = event.y
     platno.create_oval(surX-3,surY-3,surX+3,surY+3,fill="white")

platno.bind('<Button-1>', kresli)
platno.bind('<ButtonRelease-1>', pusti)
'<ButtonRelease-1>' ... pustenie ľavého tlačidla myši
'<ButtonRelease-2>' ... pustenie stredého tlačidla myši
'<ButtonRelease-3>' ... pustenie pravého tlačidla myši

Reakcia na udalosti z klávesnice

Na udalosti stlačenia klávesu použijeme metódu .bind_all('klaves', funkcia), kde funkcia je názov funkcie, ktorá sa vyvolá po stlačení klávesu 'klaves'. Kláves je konkrétny znak na klávesnici, napr. 'a' alebo 'w', alebo názov ovládacieho klávesu. Príklady ovládacích klávesov:

Volaná funkcia musí mať jeden parameter - tak ako tomu bolo v prípade volania .bind(), napríklad event. Cez tento parameter sa môžu funkcii predávať podrobnejšie informácie o udalosti. Rovnako ako pri kliknutí myši aj pri stlačení klávesu sa posielajú v tomto parametri súradnice aktuálnej pozície myši, alebo aj informácie o zatlačenom klávese.

Program, v ktorom sa vykresľujú rôzne útvary na plátno, podľa udalostí: po stlačení klávesy 's' sa vykreslí štvorec na mieste kurzoru myši, po stlačení klávesy 'k' sa vykreslí na pozícii myšky krúžok, po stlačení šípky hore, dole resp. vpravo sa na mieste kurzoru myši vykreslí odpovedajúca šípka.

Príklad: Udalosti od myšky a klávesnice

import tkinter, random
platno = tkinter.Canvas(width=500, height=400, bg="white")
platno.pack()

def stvorec(event):
    nx = event.x
    ny = event.y
    platno.create_rectangle(nx-10,ny-10,nx+10,ny+10)

def kruh(event):
    nx = event.x
    ny = event.y
    platno.create_oval(nx-10,ny-10,nx+10,ny+10)

def sipka_hore(event):
    nx = event.x
    ny = event.y
    platno.create_line(nx-10,ny+20,nx,ny,nx+10,ny+20)
    platno.create_line(nx,ny,nx,ny+40)

def sipka_dole(event):
    nx = event.x
    ny = event.y
    platno.create_line(nx-10,ny-20,nx,ny,nx+10,ny-20)
    platno.create_line(nx,ny,nx,ny-40)

platno.bind_all('s', stvorec)
platno.bind_all('k', kruh)
platno.bind_all('<Up>', sipka_hore)
platno.bind_all('<Down>', sipka_dole)

Úlohy na vlastnú prácu

Úloha 1: Piškvorky

Vytvor prostredie pre hru piškvorky pre dvoch hráčov.

Pomôcka:
Najprv si vytvorte herný plán a potom zabezpečte, aby ľavým tlačidlom myši kreslilo na mieste kliknutia červené prstence (červený kruh v strede s bielym kruhom) a pravým tlačidlom modré krížiky (dve hrubšie modré čiary).

import tkinter
platno = tkinter.Canvas(bg="white", width=300, height=300)
platno.pack()

def plan():
    for i in range(1,300,30):
        platno.create_line(i,0,i,300)
        platno.create_line(0,i,300,i)
plan()

Úloha 2: Kreslenie myškou

Vytvor program, ktorý bude pri ťahaní myškou kresliť šikmú hrubšiu čiaru (ako hrot kaligrafického pera), jej farba nech je náhodná.

Pomôcka:
Funkcia na voľbu náhodnej pastelovej farby vo forme napr.'#A3F5B2'

def nahodna_farba_hex():
    return f"#{random.randint(0x808080, 0xFFFFFF):06x}"

Úloha 3: Pohyb planéty

Vytvor program, ktorý pri kliknutí na plátno na zvolené miesto vykreslí planétu Zem (obrázok zo súboru globe.png) a pri stláčaní klávesov so šípkami sa bude zemeguľa pohybovať zvoleným smerom (na jedno zatlačenie o 10 pixelov).

Pomôcka:
Funkcia na vykreslenie planéty zo súboru 'globe.png' na plátno:

zem=tkinter.PhotoImage(file="globe.png")
def kresli(event):
    global co
    surX = event.x
    surY = event.y
    co=platno.create_image(surX,surY,image=zem)

Overenie vedomostí

Test - Udalosti

1. Čo robí metóda platno.move(objekt, x, y)?

a) Presunie celé plátno o dané súradnice
b) Presunie daný objekt o relatívnu hodnotu x, y
c) Nastaví absolútne súradnice objektu
d) Duplikuje prvok na novú pozíciu

2. Aký je rozdiel medzi metódami move() a coords() v tkinteri (Canvas)?

a) move() zmení farbu objektu, coords() nastaví jeho polohu
b) move() presúva relatívne, coords() nastavuje absolútne súradnice
c) move() presúva absolútne, coords() relatívne
d) Obe robia to isté

3. Čo robí metóda itemconfig()?

a) Aktualizuje všetky objekty na plátne
b) Odstraňuje daný prvok z plátna
c) Presúva objekt po plátne
d) Umožňuje zmeniť vlastnosti (napr. farbu, text, hrúbku čiary) objektu

4. Čo robí metóda platno.bind('udalost', obsluha) v Tkinteri?

a) Priradí funkciu obsluha na spracovanie udalosti pre dané plátno
b) Trvalo mení farbu plátna
c) Priradí funkciu obsluha pre všetky plátna v okne
d) Ukončí aplikáciu po výskyte udalosti

5. Aký je hlavný rozdiel medzi bind() a bind_all()?

a) bind_all() funguje len na tlačidlá myši
b) bind() viaže udalosť na konkrétne plátno, bind_all() na všetko v aplikácii
c) bind_all() je zastaraný príkaz
d) bind() viaže udalosť iba na hlavné okno aplikácie

6.Čo obsahuje parameter event odovzdaný do funkcie obsluhy?

a) Len názov udalosti
b) Informácie o type udalosti, pozícii myši, a stave kláves
c) Len čas udalosti
d) Nič, ak sa neaktivuje bind_all()

7. Ktorý reťazec správne reprezentuje kliknutie ľavým tlačidlom myši?

a) "<Mouse-1>"
b) "<LeftClick>"
c) "<Button-1>"
d) "<Click-Left>"

8. Ktorý reťazec správne reprezentuje ťahanie so stlačeným ľavým tlačidlom myši?

a) "<Button-1>"
b) "<Motion-1>"
c) "<ButtonRelease-1>"
d) "<B1-Motion>"

9. Čo za udalosť reprezentuje raťazec "<Dounle-Button-1>"?

a) dvojklik ľavého tlačidla myši
b) ťahanie pri stlačenom ľavom tlačidle
c) pustenie ľavého tlačidla myši
d) takáto udalosť neexistuje

10. Ktorý z nasledujúcich príkazov zabezpečí, že stlačenie klávesu "Escape" ukončí aplikáciu?

a) platno.bind("<Escape>", quit)
b) platno.bind_all("<Escape>", quit)
c) platno.bind_key("<Escape>", quit)
d) platno.bind_global("<Escape>", quit)


Späť na hlavnú stránku