3. Grafika

Doteraz sme pracovali len v textovom režime: do textovej plochy (shell) sme z programu zapisovali len pomocou print(). V súčasných operačných systémoch (windows, linux, os, …) sú skoro všetky aplikácie grafické. Preto to skúsime aj my.

Budeme pracovať s modulom tkinter, ktorý slúži na vytváranie grafických aplikácii. My ho budeme využívať prakticky len na kreslenie na tzv. plátno, hoci tento modul zvláda aj iné typy grafických prvkov. Príkladom grafickej aplikácie, ktorá je kompletne napísaná v Pythone a používa tkinter je vývojové prostredie IDLE.

Užitočné informácie k tkinter nájdete napr. v materiáli:

Základná grafická aplikácia

Minimálna grafická aplikácia je táto:

import tkinter

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

# tu sa bude kreslit do grafickej plochy

tkinter.mainloop()

Príkazy majú postupne takéto vysvetlenie:

  • import tkinter - vytvorí premennú tkinter, pomocou ktorej budeme mať prístup (bodkovou notáciou) k funkciám v module

  • canvas = tkinter.Canvas() - vytvorí plátno grafickej aplikácie - priradili sme ho do premennej canvas (mohlo sa to volať hocijako inak, ale takto budeme lepšie rozumieť aj cudzím programom)

    • týmto vznikne malá grafická aplikácia (malé okno), aj plátno, ktoré ale zatiaľ nie je nikde v tejto aplikácii umiestnené

  • canvas.pack() - až teraz sa umiestni naše plátno do grafickej aplikácie (do okna) - plátno je teraz pripravené, aby sme do neho mohli kresliť

  • tkinter.mainloop() - grafická aplikácia vďaka tomuto príkazu v operačnom systéme naozaj „žije“, t.j. reaguje na klikanie, presúvanie, zmenu veľkosti, prekresľovanie, …

Posledný príkaz tkinter.mainloop() môžeme pri spustení pod IDLE vynechať, lebo práve IDLE ho spraví za nás.

Po spustení tohto programu dostávame malú grafickú aplikáciu:

_images/03_01.png

V tejto aplikácii sa nachádza plátno (šedá plocha vo vnútri okna), ktoré je zatiaľ prázdne, lebo sme ešte nezadali žiaden ďalší grafický príkaz na kreslenie.

Grafické príkazy

Všetky grafické príkazy budú pracovať s plátnom a preto budú začínať slovom canvas, za ktorým bude samotný príkaz. Tvar väčšiny príkazov bude

canvas.create_<meno útvaru>(x, y, ..., <ďalšie parametre>)

Bude to znamenať, že do grafickej plochy canvas sa nakreslí uvedený útvar, jeho poloha súvisí so súradnicami (x, y) a niekedy budeme okrem ďalších súradníc špecifikovať aj nejaké parametre. Postupne sa zoznámime s týmito grafickými objektami:

canvas.create_text(...)           # vypíše zadaný text
canvas.create_rectangle(...)      # nakreslí obdĺžnik
canvas.create_oval(...)           # nakreslí elipsu
canvas.create_line(...)           # nakreslí lomenú čiaru
canvas.create_polygon(...)        # nakreslí polygón
canvas.create_image(...)          # nakreslí png obrázok

Text v grafickej ploche

Ukážme najjednoduchší grafický príkaz, ktorý do plochy (plátna) zapíše nejaký text. Do našej šablóny na vytvorenie grafickej aplikácie pridáme jeden príkaz na „nakreslenie“ (vypísanie) nejakého textu:

import tkinter

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

canvas.create_text(150, 100, text='programujem v Pythone')

Po spustení dostávame takýto grafický výstup:

_images/03_02.png

V šedej ploche sa na súradniciach (150, 100) vypísal zadaný text ale dosť malými písmenkami. Potrebujeme ale rozumieť, ako tkinter chápe súradnicovú sústavu.

Súradnicová sústava

Zo školskej matematiky vieme, že súradnicové osi x a y sú na seba kolmé a pretínajú sa v bode (0, 0). Orientácia týchto osí je takáto:

_images/03_03.png

V počítačových programoch sa veľmi často bod (0, 0) presúva do ľavého horného rohu plátna, x-ová os prechádza zľava doprava po hornej hrane plátna a y-ová os prechádza zhora nadol po ľavej hrane plátna:

_images/03_04.png

Aj takáto súradnicová sústava má záporné x a y ale, keď budeme kresliť mimo viditeľnú časť plátna, niektoré časti kresby nebudeme vidieť. Zatiaľ budeme pracovať s plátnom, ktorý má rozmery približne 380 x 260. Neskôr sa naučíme nastavovať ľubovoľné rozmery plátna.

Využime generátor náhodných čísel (modul random) na generovanie náhodných bodov v grafickej ploche. Môžeme zapísať:

import tkinter
import random

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

x = random.randrange(380)
y = random.randrange(260)
canvas.create_text(x, y, text='PYTHON')

Tento program na náhodnú pozíciu umiestni text 'PYTHON'. Keď ho zavoláme viackrát, zakaždým vypíše tento istý text ale na inú pozíciu. Môžeme sa o tom presvedčiť tak, že príkazy, ktoré generujú náhodnú pozíciu a vypisujú text, necháme pomocou for-cyklu opakovať 10-krát:

import tkinter
import random

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

for i in range(10):
    x = random.randrange(380)
    y = random.randrange(260)
    canvas.create_text(x, y, text='PYTHON')

dostávame takýto obrázok:

_images/03_05.png

Stačí namiesto výpisu 'PYTHON' vypisovať premennú cyklu:

import tkinter
import random

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

for i in range(50):
    x = random.randrange(380)
    y = random.randrange(260)
    canvas.create_text(x, y, text=i)

dostávame takýchto 50 náhodne vygenerovaných bodov:

_images/03_06.png

Pri vypisovaní textov pomocou create_text môžeme použiť nielen znakové reťazce a celočíselné premenné, ale napr. aj takéto dvojice:

import tkinter
import random

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

for i in range(10):
    x = random.randrange(380)
    y = random.randrange(260)
    canvas.create_text(x, y, text=(x, y))

teraz okrem 10 náhodne vygenerovaných bodov sa dozvedáme aj ich súradnice:

_images/03_07.png

Tu treba poznamenať, že samotné súradnice vypisovaného textu označujú presný stred tohto textu, tak ako to ukazuje nasledovný zväčšený obrázok, v ktorom sa vypísal text 'PYTHON'. Je tu zobrazená aj poloha (x, y), ktorá sa zadala v príkaze create_text:

_images/03_07a.png

Kreslenie obdĺžnikov

Na nakreslenie obdĺžnikov slúži grafický príkaz:

canvas.create_rectangle(x1, y1, x2, y2)

Keďže takýto obdĺžnik bude mať strany rovnobežné s osami x a y, na jednoznačné zadefinovanie obdĺžnika nám budú stačiť ľubovoľné dva protiľahlé vrcholy. Najčastejšie to bude ľavý horný bod (x1, y1) a pravý dolný (x2, y2). Zapíšme napríklad:

import tkinter

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

canvas.create_rectangle(50, 30, 190, 110)

Nakreslí obdĺžnik, ktorého ľavý horný vrchol je (50, 30) a pravý dolný je (190, 110):

_images/03_08.png

Keďže pri kreslení obdĺžnika môžeme určiť jeho ľubovoľné dva protiľahlé vrcholy, všetky nasledovné volania by nakreslili presne ten istý obdĺžnik, ako sa nakreslil v predchádzajúcom programe:

canvas.create_rectangle(190, 110, 50, 30)
canvas.create_rectangle(50, 110, 190, 30)
canvas.create_rectangle(190, 30, 50, 110)

Uvedomte si, že šírka tohto obdĺžnika (veľkosť vodorovnej strany) je 190 - 50, teda 140 a výška je 110 - 30, teda 80. Ak by sme teraz zapísali:

import tkinter

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

x, y = 50, 30
sirka, vyska = 140, 80
canvas.create_rectangle(x, y, x + sirka, y + vyska)

dostaneme opäť ten istý obdĺžnik. Tento zápis má ale ešte jednu výhodu: veľmi jednoducho vieme nakresliť rovnaký obdĺžnik, ale na inom mieste. Stačí zmeniť x, y a obdĺžnik rozmerov 140 x 80 sa nakreslí na novej pozícii. Pomôžeme si podobne ako pri náhodných pozíciách textu aj pri kreslení obdĺžnikov na náhodné pozície pomocou funkcií modulu random. Nakreslíme 10 rovnako veľkých obdĺžnikov na náhodné pozície:

import tkinter
import random

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

for i in range(10):
    x = random.randint(10, 240)
    y = random.randint(10, 180)
    sirka, vyska = 140, 80
    canvas.create_rectangle(x, y, x + sirka, y + vyska)

Všimnite si, že obdĺžniky majú priesvitné vnútro (výplň) a teda je cez obdĺžniky vidieť:

_images/03_09.png

Teraz by sme zvládli zmeniť aj veľkosť obdĺžnikov na nejaké náhodné hodnoty. Preto vo vnútri cyklu vygenerujeme náhodné hodnoty aj pre sirka aj vyska, napríklad takto:

import tkinter
import random

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

for i in range(20):
    sirka = random.randint(10, 80)
    vyska = random.randint(10, 80)
    x = random.randint(10, 370 - sirka)
    y = random.randint(10, 260 - vyska)
    canvas.create_rectangle(x, y, x + sirka, y + vyska)

a môžeme dostať:

_images/03_10.png

Veľmi často budem pri kreslení grafických útvarov používať aj nejaké farby. Napríklad, tu by sa veľmi hodilo mať zafarbené vnútro týchto obdĺžnikov. Do predchádzajúceho programu urobíme veľmi malú zmenu: do príkazu create_rectangle doplníme jeden parameter, ktorý určí farbu výplne. Zmeňme len tento jeden riadok:

canvas.create_rectangle(x, y, x + sirka, y + vyska, fill='red')

20 vyfarbených obdĺžnikov teraz vyzerá takto:

_images/03_11.png

Zrejme teraz každý ďalší nakreslený obdĺžnik môže prekrývať (aj úplne zakryť) niektoré už pred tým nakreslené grafické útvary. Aby sme mohli využívať aj iné farby, mali by sme aspoň čiastočne pochopiť princíp, ako tkinter používa farby.

Farby v grafických programoch

V prvom rade modul tkinter akceptuje najbežnejšie mená farieb v angličtine. Tu môžete vidieť malú ukážku týchto mien aj so zodpovedajúcimi farbami:

_images/03_12.png

Tieto mená farieb vo veľkej miere zodpovedajú menám v HTML zápisoch a môžete si o tom niečo pozrieť na stránke HTML Color Names.

Ďalší príklad ilustruje použitie dvoch rôznych farieb. Do premenných farba1 a farba2 vložíme mená nejakých dvoch farieb. Potom v cykle použijeme farba1 na vyfarbenie obdĺžnika a nakoniec navzájom vymeníme obsahy týchto dvoch premenných farba1 a farba2. To znamená, že ďalší obdĺžnik sa vyfarbí už druhou farbou:

import tkinter
import random

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

farba1, farba2 = 'tomato', 'gold'
for i in range(20):
    sirka = random.randint(10, 80)
    vyska = random.randint(10, 80)
    x = random.randint(10, 370 - sirka)
    y = random.randint(10, 260 - vyska)
    canvas.create_rectangle(x, y, x + sirka, y + vyska, fill=farba1)
    farba1, farba2 = farba2, farba1

Teraz to môže vyzerať takto:

_images/03_13.png

Modul tkinter umožňuje zadávanie farieb aj pomocou tzv. RGB modelu. Každá farba je namiešaná z troch farebných zložiek: red (červená), green (zelená) a blue (modrá). Intenzita každej zložky je určená číslom medzi 0 a 255: hodnota 0 označuje, že príslušná zložka v danej farbe nie je, hodnota 255 znamená, že jej je maximálne možné. Čísla medzi tým určujú rôzne odtiene. Ukážme si, akým farbám by zodpovedali niektoré kombinácie RGB. Do troch premenných r, g, b priradíme tri čísla a zapíšeme zodpovedajúcu farbu:

r, g, b = 0, 255, 0       # zelená 'green'
r, g, b = 0, 100, 0       # tmavozelená 'dark green'
r, g, b = 255, 255, 0     # žltá 'yellow'
r, g, b = 190, 190, 190   # šedá 'gray'
r, g, b = 0, 0, 128       # tmavomodrá 'navy'
r, g, b = 255, 255, 255   # biela 'white'
r, g, b = 255, 215, 0     # zlatá 'gold'
r, g, b = 255, 165, 0     # oranžová 'orange'
r, g, b = 255, 192, 203   # ružová 'pink'

Takto definované farby sa ale musia zapísať v špeciálnom formáte, ktorý je presne rovnaký ako v HTML. Zapisuje sa ako 7-znakový reťazec v tvare:

'#rrggbb'

pričom rr označuje číslo (od 0 do 255) pre červenú zložku, ktoré je zapísané v šestnástkovej (hexadecimálnej) sústave ako dvojciferné číslo, podobne gg a bb vyjadrujú zelenú a červenú zložku, tiež ako dvojciferné šetnástkové čísla. Napríklad ružovej farbe, ktorá má rgb 255, 192, 203, zodpovedajú šestnástkové zápisy ff, c0, cb a preto ružovú farbu môžeme zapísať ako '#ffc0cb'. Našťastie nám Python pomôže v prevode ľubovoľných čísel do šestnástkovej sústavy. Môžeme otestovať:

>>> r, g, b = 255, 192, 203         # ružová farba
>>> f'#{r:02x}{g:02x}{b:02x}'
'#ffc0cb'
>>> r, g, b = 0, 100, 0             # tmavozelená farba
>>> f'#{r:02x}{g:02x}{b:02x}'
'#006400'

Použime tieto dve farby na nakreslenie radu obdĺžnikov, ktorým sa striedajú farby výplne:

import tkinter

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

y = 100
farba1, farba2 = '#ffc0cb', '#006400'
for x in range(10, 350, 30):
    canvas.create_rectangle(x, y, x + 25, y + 50, fill=farba1)
    farba1, farba2 = farba2, farba1

po spustení:

_images/03_14.png

Všimnite si takúto časť programu:

r = random.randrange(256)
g = random.randrange(256)
b = random.randrange(256)
farba = f'#{r:02x}{g:02x}{b:02x}'

Najprv sa tu vygenerovali tri náhodné celé čísla z intervalu <0, 255> (čo môžu byť tri zložky RGB) a z nich sa korektne zostavila šestnástková reprezentácia farby. Využime túto ideu a vygenerujme sieť rôznofarebných štvorcov:

import tkinter
import random

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

for y in range(5, 230, 30):
    for x in range(5, 350, 30):
        r = random.randrange(256)
        g = random.randrange(256)
        b = random.randrange(256)
        farba = f'#{r:02x}{g:02x}{b:02x}'
        canvas.create_rectangle(x, y, x + 25, y + 25, fill=farba)

Keď tento program spustíte viackrát, zakaždým dostanete iný výsledok, napríklad:

_images/03_15.png

Ak nepotrebujeme generovať tri oddelené zložky RGB, ale stačí nám jedna náhodná hodnota, môžeme použiť úspornejší variant generovania náhodnej farby:

farba = f'#{random.randrange(256**3):06x}'

V tomto prípade sa najprv vygeneruje náhodné číslo z intervalu <0, 16777215> (tretia mocnina 256 mínus 1), toto číslo sa zapíše ako 6-ciferné šestnástkové číslo (3 dvojciferné RGB zložky) do znakového reťazca aj so znakom '#' na začiatku. Použitie takto generovanej náhodnej farby ukážeme v príklade, v ktorom nakreslíme vedľa seba 8 zväčšujúcich sa štvorcov (so stranami 10, 20, 30, … 80):

import tkinter
import random

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

x, y = 5, 200
for a in range(10, 90, 10):
    farba = f'#{random.randrange(256**3):06x}'
    canvas.create_rectangle(x, y, x + a, y - a, fill=farba)
    x += a + 1

Každý nakreslený štvorec má inú náhodnú farbu. Všimnite si, že (x, y) je v tomto prípade ľavý dolný vrchol a jemu protiľahlý (pravý horný) má súradnice (x+a, y-a), teda veľkosť strany štvorca je zrejme a:

_images/03_16.png

Kreslenie elíps

Keď už vieme kresliť obdĺžniky, potom prechod k elipsám je pre tkinter veľmi jednoduchý: napíšeme program s kreslením obdĺžnikov a potom namiesto create_rectangle zapíšeme create_oval - namiesto obdĺžnika sa presne na tom istom mieste nakreslí (vpísaná) elipsa - vlastne sa „zaoblia“ rohy obdĺžnika. Ukážme to na príklade, v ktorom nakreslíme obdĺžnik a potom na tom istom mieste (s tými istými súradnicami) nakreslíme elipsu:

import tkinter

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

canvas.create_rectangle(80, 50, 300, 200)
canvas.create_oval(80, 50, 300, 200, fill='white')

Nakreslenú elipsu sme zafarbili na bielo, aby ju bolo lepšie vidieť:

_images/03_17.png

Otestujme kreslenie elíps na programe, v ktorom sme kreslili náhodne veľké obdĺžniky na náhodné pozície. Namiesto create_rectangle zapíšeme create_oval:

import tkinter
import random

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

for i in range(20):
    sirka = random.randint(10, 80)
    vyska = random.randint(10, 80)
    x = random.randint(10, 370 - sirka)
    y = random.randint(10, 260 - vyska)
    canvas.create_oval(x, y, x + sirka, y + vyska)

Program nakreslí 20 rôzne veľkých elíps:

_images/03_18.png

Zrejme ste si uvedomili, že elipsa, ktorá vznikne zo štvorca (má rovnakú šírku a výšku), je kružnica. Hoci kružnice sa často kreslia tak, že zadáme súradnice stredu (x, y) a polomer r. Potom sa kružnica kreslí takto jednoducho:

import tkinter

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

x, y = 150, 100
r = 80
canvas.create_oval(x - r, y - r, x + r, y + r)

canvas.create_text(x, y, text='+')

Na pozíciu stredu sme dokreslili krížik:

_images/03_19.png

V ďalšom programe nakreslíme 100 rôznofarebných kruhov s polomerom r=20 na náhodné pozície:

import tkinter
import random

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

for i in range(100):
    x = random.randint(20, 350)
    y = random.randint(20, 240)
    r = 20
    fill = f'#{random.randrange(256**3):06x}'
    canvas.create_oval(x - r, y - r, x + r, y + r, fill=fill)

Všimnite si premennú fill, do ktorej priradíme náhodnú farbu. Vďaka tomu pri volaní príkazu create_oval zapisujeme fill=fill aby sme pomenovanému parametru fill priradili hodnotu premennej fill. Po spustení dostaneme:

_images/03_20.png

Kreslenie úsečiek a lomených čiar

Ďalším grafickým príkazom kreslíme lomené čiary, t.j. čiary, ktoré sa skladajú z nadväzujúcich úsečiek. Tvar príkazu je:

canvas.create_line(x1, y1, x2, y2, x3, y3, ...)

Parametrom je postupnosť súradníc, ktoré tvoria lomenú čiaru. Táto postupnosť musí obsahovať aspoň 2 body - vtedy sa nakreslí jedna úsečka. Napíšme program, ktorý nakreslí 100 úsečiek, ktoré majú prvý bod v (0, 0) a druhý je náhodný v ploche:

import tkinter
import random

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

for i in range(100):
    x = random.randint(20, 380)
    y = random.randint(20, 260)
    canvas.create_line(0, 0, x, y)

po spustení:

_images/03_21.png

Doteraz sme používali takéto paralelné priradenie:

x, y = 100, 150

Do dvoch premenných x a y sa priradia nejaké dve hodnoty. Lenže Python ponúka ešte aj takýto variant priradenia:

a = 100, 150

V tomto prípade sa do premennej a priradí dvojica celých čísel. Takéto dvojice môžeme potom použiť ako parametre do grafických príkazov. Napríklad zadefinujeme tri dvojice čísel, teda súradnice troch bodov a, b, c a potom nakreslíme trojuholník pomocou troch úsečiek:

import tkinter

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

a = 100, 150
b = 280, 210
c = 170, 40

canvas.create_line(a, b)
canvas.create_line(b, c)
canvas.create_line(c, a)

a vyzerá to takto:

_images/03_22.png

Tri volania create_line môže spojiť do jedného a ešte k tomu pridáme aj pomenovanie týchto vrcholov reťazcami 'A', 'B', 'C':

import tkinter

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

a = 100, 150
b = 280, 210
c = 170, 40

canvas.create_line(a, b, c, a)

canvas.create_text(a, text='A')
canvas.create_text(b, text='B')
canvas.create_text(c, text='C')

Všimnite si, že aj v grafických príkazoch create_text sme použili premenné, ktoré sú dvojicami celých čísel. Program nakreslí:

_images/03_23.png

Body na kružnici

Už vieme kresliť kružnicu (x0, y0) s polomerom r napríklad takto:

canvas.create_oval(x - r, y - r, x + r, y + r)

Lenže často riešime úlohy, v ktorých potrebujeme nie celú kružnicu, ale len niekoľko bodov na jej obvode. Využijeme goniometrické funkcie sin a cos. Potom každý bod na kružnici môžeme zapísať takýmto vzorcom:

x = x0 + r * cos(uhol)
y = y0 + r * sin(uhol)

kde uhol je zrejme nejaké číslo od 0 do 360 (nemusí byť celé). Zapíšme program, ktorý nakreslí lúče medzi stredom a bodmi na kružnici:

import tkinter
from math import sin, cos, radians

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

x0, y0 = 150, 130
r = 110

for uhol in range(0, 360, 15):
    x = x0 + r * cos(radians(uhol))
    y = y0 + r * sin(radians(uhol))
    canvas.create_line(x0, y0, x, y)
    canvas.create_text(x, y, text=uhol)

Program nakreslí 24 úsečiek, ktorých druhé konce sú rovnomerne rozmiestnené po obvode kružnice (po 15 stupňoch). Ku každej tejto úsečke sme pripísali aj ich prislúchajúci uhol:

_images/03_24.png

Ešte ukážeme využitie tejto idey na vypisovanie nejakého textu po jednotlivých znakoch tak, že ich rovnomerne rozložíme po obvode kružnice. V tomto prípade nebudeme kresliť úsečky, vypíšeme len znaky textu. Keďže text vieme rozobrať na znaky len pomocou for-cyklu (napr. for znak in text), premennú uhol budeme musieť zväčšovať priraďovaním v tele cyklu:

import tkinter
from math import sin, cos, radians

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

x0, y0 = 150, 130
r = 110

text = input('zadaj text: ')
n = len(text)
uhol, posun = 0, 360 / n

for znak in text:
    x = x0 + r * cos(radians(uhol))
    y = y0 + r * sin(radians(uhol))
    canvas.create_text(x, y, text=znak)
    uhol += posun

Použili sme tu štandardnú funkciu len, ktorá pre zadaný reťazec vráti počet znakov (tzv. dĺžka znakového reťazca). Keď zadáme vstupný reťazec 'programovanie', dostaneme:

_images/03_25.png

Tu by sa oplatilo vedieť vypísať písmená tohto textu trochu väčším fontom. Na to slúži pomenovaný parameter font. Keď riadok s výpisom textu nahradíme:

canvas.create_text(x, y, text=znak, font='arial 35')

Program teraz na výpis textu použije font 'Arial' a veľkosť znakov bude 35 (v rôznych operačných systémoch môže tento parameter dávať trochu rozdielne výsledky). Dostávame:

_images/03_26.png

Kreslenie polygónov

Polygónom voláme oblasť grafickej plochy, ktorá je ohraničená zadanou lomenou čiarou (aspoň s tromi vrcholmi) a vyplní sa nejakou farbou. Body zadávame podobne ako pre create_line. Zrejme, keby sme zadali len dva body, bolo by to asi málo. Táto oblasť bude zafarbená čiernou farbou, prípadne ju môžeme zmeniť pomocou pomenovaného parametra fill, napríklad takto:

import tkinter

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

a = (100, 50)
b = (30, 150)
c = (160, 120)
d = (180, 40)
canvas.create_polygon(a, b, c, d, fill='blue')

a vyzerá to takto:

_images/03_27.png

Všimnite si, že nakreslená oblasť (polygón) nemá nakreslený obrys. Ak by sme ho chceli vidieť, zadali by sme aj pomenovaný parameter outline.

Nasledovný program nakreslí n rovnostranných trojuholníkov, pričom všetky majú rovnakú veľkosť stranoy a. Trojuholníky budú v ploche umiestnené náhodne, t.j. nielen ich poloha bude náhodná, ale aj ich otočenie. okrem toho každý z nich zafarbíme náhodnou farbou. Pri kreslení náhodného trojuholníka použijeme takúto ideu:

  1. zvolíme náhodné súradnice prvého vrcholu (pre istotu nie úplne blízko okrajov grafickej plochy)

  2. zvolíme náhodný uhol otočnia trojuholníka

  3. vypočítame druhý vrchol, ako bod na kružnici so stredom prvého vrcholu a s polomerom veľkosti strany trojuholníka

  4. tretí vrchol trojuholníka leží na tej istej kružnici ako druhý vrchol, ale je o 60 stupňov otočený vľavo (alebo vpravo) optoti druhému vrcholu

Teraz máme istotu, že tieto tri vrcholy tvoria rovnostranný trojuholník so straou a (je to rovnoramenný trojuholník, v ktorom je medzi ramenami uhol 60 stupňov).

Všimnite si, ako sme v tomto programe vyriešili importy zo všetkých troch modulov:

from tkinter import Canvas
from random import randint, randrange
from math import sin, cos, radians

canvas = Canvas()
canvas.pack()

a = 30
n = 100

for i in range(n):
    x1 = randint(a, 380 - a)
    y1 = randint(a, 260 - a)
    uhol = randrange(360)
    x2 = x1 + a * cos(radians(uhol))
    y2 = y1 + a * sin(radians(uhol))
    uhol = uhol - 60
    x3 = x1 + a * cos(radians(uhol))
    y3 = y1 + a * sin(radians(uhol))
    farba = f'#{randrange(256**3):06x}'
    canvas.create_polygon(x1, y1, x2, y2, x3, y3, fill=farba)

Po spustení dostávame:

_images/03_28.png

Grafický objekt obrázok

Aby sme do plochy mohli nakresliť nejaký obrázok, musíme najprv vytvoriť „obrázkový objekt“ (pomocou tkinter.PhotoImage() prečítať obrázok zo súboru) a až tento poslať ako parameter do príkazu na kreslenie obrázkov canvas.create_image().

Obrázkový objekt vytvoríme špeciálnym príkazom:

premenna = tkinter.PhotoImage(file='meno suboru')

v ktorom meno suboru je súbor s obrázkom vo formáte png alebo gif. Takýto obrázkový objekt môžeme potom vykresliť do grafickej plochy ľubovoľný počet-krát.

Samotná funkcia canvas.create_image() na vykreslenie obrázka má tri parametre: prvé dva sú súradnice stredu vykresľovaného obrázka a ďalší pomenovaný parameter určuje obrázkový objekt. Príkaz má tvar:

canvas.create_image(x, y, image=premenna)

Napr.

obr = tkinter.PhotoImage(file='python.png')
canvas.create_image(500, 100, image=obr)

Parametre grafickej plochy

Pri vytváraní grafickej plochy (pomocou tkinter.Canvas()) môžeme nastaviť veľkosť plochy ale aj farbu pozadia grafickej plochy. Môžeme uviesť tieto parametre:

  • bg = nastavuje farbu pozadia (z anglického „background“)

  • width = nastavuje šírku grafickej plochy

  • height = výšku plochy

Napr.

canvas = tkinter.Canvas(bg='white', width=400, height=200)

Vytvorí bielu grafickú plochu, ktorá má šírku 400 a výšku 200.

Zhrnutie parametrov grafických príkazov

texty

canvas.create_text(x, y, ...)        # súradnica jedného bodu
  • text = vypisovaný text

  • font = písmo a veľkosť

    • buď 'meno veľkosť' pre jednoslovné meno fontu

    • alebo ('meno', veľkosť)

  • fill = farba textu

  • angle = uhol otočenia v stupňoch

  • anchor = ukotvenie (pozícia (x, y))

    • , jedno z 'center', 'nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'

obdĺžniky

canvas.create_rectangle(x, y, x, y, ...)     # súradnice dvoch bodov
  • width = hrúbka obrysu

    • hodnota 0 označuje bez obrysu

  • outline = farba obrysu

    • hodnota '' označuje bez obrysu

  • fill = farba výplne

    • hodnota '' označuje bez výplne

elipsy

canvas.create_oval(x, y, x, y, ...)       # súradnice dvoch bodov
  • width = hrúbka obrysu

    • hodnota 0 označuje bez obrysu

  • outline = farba obrysu

    • hodnota '' označuje bez obrysu

  • fill = farba výplne

    • hodnota '' označuje bez výplne

lomené čiary

canvas.create_line(x, y, x, y, x, y, x, y, ...)      # súradnice aspoň dvoch bodov
  • width = hrúbka čiary

  • fill = farba čiary

  • arrow = šípka na konci čiary

    • jedno z 'first', 'last', 'both'

polygóny

canvas.create_polygon(x, y, x, y, x, y, x, y, ...)       # súradnice aspoň dvoch bodov
  • width = hrúbka obrysu

    • hodnota 0 označuje bez obrysu

  • outline = farba obrysu

    • hodnota '' označuje bez obrysu

  • fill = farba výplne

    • hodnota '' označuje bez výplne


Zmeny nakreslených útvarov

Všetky útvary, ktoré kreslíme do grafickej plochy si systém pamätá tak, že ich dokáže dodatočne meniť (napr. ich farbu), posúvať po ploche, ale aj mazať. Všetky útvary sú v ploche vykresľované presne v tom poradí, ako sme zadávali jednotlivé grafické príkazy: skôr nakreslené útvary sú pod neskôr nakreslenými a môžu ich prekrývať.

Každý grafický príkaz (napr. canvas.create_line()) je v skutočnosti funkciou, ktorá vracia celé číslo - identifikátor nakresleného útvaru. Toto číslo nám umožní neskoršie modifikovanie, resp. jeho zmazanie.

Okrem tohto identifikačného čísla (každý objekt má jedinečné číslo), môžeme grafickým objektom prideľovať štítky (pomenovaný parameter tag=) a potom môžeme vo všetkých nasledovných príkazov namiesto identifikátora používať tento pridelený štítok. Pritom rôzne objekty môžu mať rovnaké štítky a tým môžeme jedným modifikačným príkazom zmeniť naraz viac objektov.

Zrušenie nakresleného útvaru

Na zrušenie ľubovoľných grafických objektov z grafickej plochy slúži funkcia:

canvas.delete(oznacenie)

kde parameter oznacenie je jedno z

  • číselný identifikátor

  • pridelený štítok (tag)

  • reťazec 'all' označuje všetky útvaru v ploche

Napr.

id1 = canvas.create_line(10, 20, 30, 40)
id2 = canvas.create_oval(10, 20, 30, 40)
canvas.create_text(100, 100, text='ahoj', tag='t')
canvas.create_rectangle(80, 90, 120, 110, fill='gray', tag='t')
...
canvas.delete(id1)
canvas.delete('t')

Zmaže prvý grafický objekt, t.j. úsečku, pričom druhý objekt kružnica ostáva bez zmeny. Druhý príkaz zmaže oba textový objekt aj obdĺžnik, ktorým sme pridelili štítok ‚t‘.

Posúvanie útvarov

Objekty môžeme posúvať určením buď identifikátora útvaru alebo jeho štítku (vtedy ich môže byť aj viac). Ostatné útvary sa pri tom nehýbu. Tvar funkcie je

canvas.move(oznacenie, dx, dy)

kde

  • označenie je buď identifikátor alebo štítok grafických útvarov (bude fungovať aj reťazec 'all')

  • dx a dy označujú číselné hodnoty zmeny súradníc útvaru, t.j. posun v smere osi x a v smere osi y

Napr.

id1 = canvas.create_line(10, 20, 30, 40)
id2 = canvas.create_oval(10, 20, 30, 40)
canvas.create_text(100, 100, text='ahoj', tag='t')
canvas.create_rectangle(80, 90, 120, 110, fill='gray', tag='t')
...
canvas.move(id1, -5, 10)
canvas.move('t', -5, 10)

posunie prvý nakreslený útvar, teda úsečku, druhý útvar (kružnicu) pri tom nehýbe, zároveň s tým posunie naraz obdĺžnik s textom.

Zmena parametrov útvaru

Táto funkcia umožňuje meniť ľubovoľné pomenované parametre už nakresleným útvarom. Jeho tvar je:

canvas.itemconfig(oznacenie, parametre)

kde

  • označenie je buď identifikátor alebo štítok grafických útvarov

  • parametre sú pomenované parametre v rovnakom formáte, aký bol pri ich vytváraní

Napr.

i = canvas.create_rectangle(80, 90, 120, 110, fill='gray')
...
canvas.itemconfig(i, fill='red')

zmení farbu výplne na červenú obdĺžnika s daným identifikačným číslom.

Zmena súradníc

Okrem posúvania útvarov im môžeme zmeniť aj ich kompletnú postupnosť súradníc. Napr. pre canvas.create_line() alebo canvas.create_polygon() môžeme zmeniť aj počet bodov útvaru. Tvar tejto funkcie je:

canvas.coords(oznacenie, postupnost)

kde

  • označenie je buď identifikátor alebo štítok grafických útvarov

  • postupnost je ľubovoľná postupnosť súradníc, ktorá je vhodná pre daný útvar - táto postupnosť musí obsahovať párny počet čísel (celých alebo desatinných)

Napr.

i1 = canvas.create_line(10, 20, 30, 40)
canvas.coords(i1, 30, 40, 50, 60, 70, 90)



Cvičenia

L.I.S.T.

  1. Zo stránky Štátne vlajky si vyber aspoň jednu vlajku, na ktorej sú vodorovné alebo zvislé pruhy farieb a nakresli ju do grafickej plochy (zvo2 si napr. Francúzsko, Nemecko, Taliansko, Belgicko, Maďarsko, …). Daj pozor, aby sa na vlajkách neobjavili čierne obrysy obdĺžnikov.

    • napr. francúzska štátna vlajka

      _images/03_c01.png

  1. Nakresli nórsku štátnu vlajku.

    • napr.

      _images/03_c02.png

  1. Na tmavomodré pozadie (napr. 'navy') nakresli na náhodné pozície n žltých hviezdičiek (create_text) znak '*' - skús ich kresliť rôznymi veľkosťami fontu (napr. veľkosť fontu nech je náhodne číslo od 10 do 20).

    • napr.

      _images/03_c03.png

  1. Nakresli dopravné značky prejazd zakázaný a zákaz zastavenia.

    • napr.

      _images/03_c04.png

  1. Nakresli n sústredných štvorcov (štvorce majú spoločný stred), v ktorých sa striedajú nejaké tri dané farby. Veľkosti štvorcov nech sú napr. 10, 20, 30, …

    • napr.

      _images/03_c05.png

  1. Nakresli pyramídu z n obdĺžnikov. Všetky sú zafarbené rovnakou náhodnou farbou. Veľkosti obdĺžnikov nech sú napr. 10x10, 20x10, 30x10, …

    • napr.

      _images/03_c06.png

  1. Program nakreslí n náhodných mincí. Mincami sú farebné kruhy s polomerom 20, v ktorých sú veľké náhodné číslice od 1 do 9.

    • napr.

      _images/03_c07.png

  1. Program najprv prečíta nejaký text zo vstupu (input) a potom postupne každé písmeno tohto textu zapíše do jedného farebného štvorca veľkosti 30x30. Tieto štvorce sú umiestnené tesne vedľa seba. Farby štvorcov aj písmen zvoľ náhodne.

    • napr.

      _images/03_c08.png

  1. Napíš program, ktorý postupne generuje n náhodných bodov a spája ich (create_line) s predchádzajúcim. Každá nakreslená čiara má nejakú náhodnú farbu.

    • napr.

      _images/03_c09.png

  1. Pre dané n nakresli n x n štvorcovú sieť. Každý štvorček zafarbí náhodne buď bielou alebo čiernou. Veľkosť štvorčekov vypočítaj tak, aby sa celá štvorcová sieť zmestila do grafickej plochy. (Nepoužívaj if.)

    • napr.

      _images/03_c10.png

  1. Napíš program, ktorý vygeneruje n náhodne zafarbených štvorčekov veľkosti 20x20. Ich pozície sa budú generovať náhodne, ale budú v štvorcovej sieti (násobky 20).

    • napr.

      _images/03_c11.png

  1. Program nakreslí 20 tesne vedľa seba ležiacich štvorcov. Tieto štvorce majú náhodné veľkostí 10 až 30, náhodné farby a ich spodná strana má rovnaké y.

    • napr.

      _images/03_c12.png

  1. Program nakreslí 25 obdĺžnikov veľkosti 15x250, ktoré sú uložené tesne vedľa seba. Tieto obdĺžniky postupne menia farby od červenej k modrej: čím je väčšie x obdĺžnika tým menej červenej a viac modrej

    • napr.

      _images/03_c13.png

  1. Program pre dané n nakreslí pravidelný n-uholník. Využi body na kružnici so stredom x a y a s polomerom r.

    • napr.

      _images/03_c14.png

  1. Podobne ako príklad (14) nakreslí pravidelný n-uholník, ale dokreslí do neho aj všetky uhlopriečky.

    • napr.

      _images/03_c15.png

  1. Program pre dané n nakreslí n dotýkajúcich sa kruhov, ktorých stredy ležia na obvode kružnice. Tieto kruhy zafarbi náhodnými farbami.

    • napr.

      _images/03_c16.png