Tkinter
Canvas Widget
Widget třídy Canvas (plátno) poskytuje grafické objekty pro Tkinter. Mezi těmito objekty jsou čáry, kružnice, obrázky a další. V tomto widgetu je možné kreslit diagramy a grafy, vytvářet grafické editory a používat různé druhy uživatelských objektů.
V našem prvním příkladě si ukážeme jak kreslit přímku.
Pro kreslení přímky použijeme metodu create_line(coords, options). Souřadnice "coords" jsou dány čtyřmi celými čísly: x1, y1, x2, y2. To znamená, že přímka vychází z bodu (x1, y1) do bodu (x2, y2).
Po těchto souřadnicích následuje seznam dalších parametrů, který může být prázdný. Nastavíme na příklad barvu čáry na speciální zelenou naší webové stránky: fill="#476042".
Tento první příklad je záměrně velmi jednoduchý. Vytvoříme plátno a nakreslíme do něho vodorovnou přímku. Tato přímka dělí plátno na dvě oblasti.
Zadání (casting) celočíselné hodnoty v přiřazení "y = int(canvas_height / 2)" je nadbytečné, protože metoda create_line umí pracovat i s hodnotami "float". Následuje kód našeho prvního jednoduchého skriptu:
from tkinter import *
master = Tk()
canvas_width = 80
canvas_height = 40
w = Canvas(master, 
           width=canvas_width,
           height=canvas_height)
w.pack()
y = int(canvas_height / 2)
w.create_line(0, y, canvas_width, y, fill="#476042")
mainloop()
Když tento program spustíme, dostaneme následující okno:
Pro kreslení obdélníků máme metodu create_rectangle(coords, options). Obdélník je definován souřadnicemi jeho rohů a to levého horního a pravého dolního.
Obrázek, který vidíte nahoře, je vytvořen následujícím kódem:
from tkinter import * master = Tk() w = Canvas(master, width=200, height=100) w.pack() w.create_rectangle(50, 20, 150, 80, fill="#476042") w.create_rectangle(65, 35, 135, 65, fill="yellow") w.create_line(0, 0, 50, 20, fill="#476042", width=3) w.create_line(0, 100, 50, 80, fill="#476042", width=3) w.create_line(150,20, 200, 0, fill="#476042", width=3) w.create_line(150, 80, 200, 100, fill="#476042", width=3) mainloop()Následující obrázek se souřadnicemi nám pomůže pochopit použití instrukcí create_line a create_rectangle v našich předchozích příkladech.
Text na plátně
Nyní si ukážeme, jak dostat text do widgetu canvas. Za tím účelem rozšíříme a upravíme předchozí příklad.Použijeme metodu create_text(x,y, options). První dva parametry jsou souřadnice textového objektu na plátně. Implicitně je text umisťován do středu. Tuto volbu lze přepsat použitím parametru anchor="w, nw, n, ne, e, se, s, sw". Pravý dolní roh má orientaci NW! Zamýšlený text zavedeme parametrem text="něco"
from tkinter import *
canvas_width = 200
canvas_height = 100
colours = ("#476042", "yellow")
box=[]
for ratio in ( 0.2, 0.35 ):
    box.append( (canvas_width * ratio,
                canvas_height * ratio,
                canvas_width * (1 - ratio),
                canvas_height * (1 - ratio) ) )
master = Tk()
w = Canvas(master, 
           width=canvas_width, 
           height=canvas_height)
w.pack()
for i in range(2):
    w.create_rectangle(box[i][0], box[i][1],
	               box[i][2], box[i][3],
	               fill=colours[i])
w.create_line(0, 0,                 # origin of canvas
              box[0][0], box[0][1], # left upper corner of the box[0]
              fill=colours[0], 
              width=3)
w.create_line(0, canvas_height,     # lower left corner of canvas
              box[0][0], box[0][3], # lower left corner of box[0]
              fill=colours[0], 
              width=3)
w.create_line(box[0][2],box[0][1],  # right upper corner of box[0] 
              canvas_width, 0,      # right upper corner of canvas
              fill=colours[0], 
              width=3)
w.create_line(box[0][2], box[0][3], # lower right corner pf box[0]
              canvas_width, canvas_height, # lower right corner of canvas
              fill=colours[0], width=3)
w.create_text(canvas_width / 2,
              canvas_height / 2,
              text="Python")
mainloop()
I když se kód našeho ukázkového programu drasticky změnil, grafický výstup je stejný až na text "Python":
Užitečnost nového kódu nahlédnete, když např. změníte výšku plátna na 190 a šířku na 90 a změníte poměr pro první rámeček na 0.3. Představte si, že byste to dělali v našem prvním příkladě. Bylo by to mnohem těžší. Výsledek vypadá takto:
Oválné objekty
Ovál (nebo ovoid) je jakákoliv křivka, která připomíná vejce (ovum je v Latině vejce). Připomíná elipsu ale není to elipsa. Oválné tvary se špatně definují. Různé křivky, označené jako ovály mají však řadu společných rysů:- Jsou to křivky derivovatelné, jednoduché (neprotínající se), konvexní, uzavřené a rovinné.
 - Tvarem se podobají elipse
 - Mají alespoň jednu osu symetrie
 
Na plátně "C" můžeme vytvořit ovál pomocí následující metody:
ov = C.create_oval ( x0, y0, x1, y1, option, ... )
Následující skript nakreslí kružnici kolem bodu (75,75) s poloměrem 25:
from tkinter import *
canvas_width = 190
canvas_height =150
master = Tk()
w = Canvas(master, 
           width=canvas_width, 
           height=canvas_height)
w.pack()
w.create_oval(50,50,100,100)
mainloop()
Můžeme definovat jednoduchou funkci, která kreslí kružnici pomocí metody create_oval():
def circle(canvas,x,y, r):
    ov = canvas.create_oval(x-r,y-r,x+r,y+r)
    return ov
Interaktivní kreslení
Chceme napsat aplikaci pro kreslení nebo psaní do plátna. Žel, nakreslit jen jeden bod do plátna nejde. Můžeme však tento problém překonat s použitím malého oválu:
from tkinter import *
canvas_width = 500
canvas_height = 150
def paint( event ):
    python_green = "#476042"
    x1, y1 = ( event.x - 1 ), ( event.y - 1 )
    x2, y2 = ( event.x + 1 ), ( event.y + 1 )
    w.create_oval( x1, y1, x2, y2, fill = python_green )
master = Tk()
master.title( "Painting using Ovals" )
w = Canvas(master, 
           width=canvas_width, 
           height=canvas_height)
w.pack(expand = YES, fill = BOTH)
w.bind( "", paint )
message = Label( master, text = "Press and Drag the mouse to draw" )
message.pack( side = BOTTOM )
    
mainloop()
 
Kreslení polygonů
Chcete-li nakreslit polygon, musíte zadat souřadnice alespoň tří bodů:create_polygon(x0,y0, x1,y1, x2,y2, ...)
Pomocí této metody nakreslíme v následujícím příkladě trojúhelník:
from tkinter import *
canvas_width = 200
canvas_height =200
python_green = "#476042"
master = Tk()
w = Canvas(master, 
           width=canvas_width, 
           height=canvas_height)
w.pack()
points = [0,0,canvas_width,canvas_height/2, 0, canvas_height]
w.create_polygon(points, outline=python_green, 
            fill='yellow', width=3)
mainloop()
Vypadá takto:
V následující ukázce si nakreslíme hvězdičku, která by se nám mohla hodit třeba o vánocích. Mnoho programovacích zkušeností k tomu potřebovat nebudeme:
from tkinter import *
canvas_width = 200
canvas_height =200
python_green = "#476042"
master = Tk()
w = Canvas(master, 
           width=canvas_width, 
           height=canvas_height)
w.pack()
points = [100, 140, 110, 110, 140, 100, 110, 90, 100,
          60, 90, 90, 60, 100, 90, 110]
w.create_polygon(points, outline=python_green, 
                 fill='yellow', width=3)
mainloop()
Jak jsme již uvedli, tento přístup je poněkud začátečnický. Co kdybychom potřebovali měnit velikost nebo obrys hvězdy? Museli bychom všechny body ručně změnit, což je pracné a náchylné k chybě. Předkládáme novou verzi předchozího skriptu, která představuje "více potu na cvičišti, méně krve na bojišti". Vytvoření hvězdy vložíme do funkce, kde polohu a tvar odvodíme od počátečního bodu a dvou parametrických délek p a t:
Náš vylepšený program vypadá takto:
from tkinter import *
canvas_width = 400
canvas_height =400
python_green = "#476042"
def polygon_star(canvas, x,y,p,t, outline=python_green,
                 fill='yellow', width = 1):
    points = []
    for i in (1,-1):
        points.extend((x,	      y + i*p))
        points.extend((x + i*t, y + i*t))
        points.extend((x + i*p, y))
        points.extend((x + i*t, y - i * t))
    print(points)
    canvas.create_polygon(points, outline=outline, 
                         fill=fill, width=width)
master = Tk()
w = Canvas(master, 
           width=canvas_width, 
           height=canvas_height)
w.pack()
p = 50
t = 15
nsteps = 10
step_x = int(canvas_width / nsteps)
step_y = int(canvas_height / nsteps)
for i in range(1, nsteps): 
    polygon_star(w, i*step_x, i*step_y, p, t,
            	outline='red' ,fill='gold', width=3)
    polygon_star(w, i*step_x, canvas_height - i*step_y, 
		 p, t, outline='red', fill='gold', width=3)
mainloop()
Hvězdičky přímo vánočně cinkají a jsme si jisti, že nikdo nepochybuje o tom, že by to bylo peklo, kdybychom museli určovat body polygonů tak, jak jsme to dělali v první verzi příkladu:
 
Bitmapy
Pro vložení bitmapového obrázku do plátna použijeme metodu create_bitmap().Pro všechny platformy jsou dostupné tyto standardní bitmapy
"error", "gray75", "gray50", "gray25", "gray12", "hourglass", "info", "questhead", "question", "warning"
Následující skript vloží všechny tyto bitmapy do plátna:
from tkinter import *
canvas_width = 300
canvas_height =80
master = Tk()
canvas = Canvas(master, 
                width=canvas_width, 
                height=canvas_height)
canvas.pack()
bitmaps = ["error", "gray75", "gray50", "gray25", "gray12",
           "hourglass", "info", "questhead", "question", "warning"]
nsteps = len(bitmaps)
step_x = int(canvas_width / nsteps)
for i in range(0, nsteps):
    canvas.create_bitmap((i+1)*step_x - step_x/2,50, bitmap=bitmaps[i])
mainloop()
Výsledek vypadá takto:
Prvek Image třídy Canvas
Pro vykreslení obrázku na plátno se používá metoda create_image(x0,y0, options ...), která ale nepřijímá obrázek přímo. Místo toho používá objekt, vytvořený metodou PhotoImage(). Tato metoda umí číst jenom obrázky v souborech s příponou GIF a PGM/PPM.
from tkinter import *
canvas_width = 300
canvas_height =300
master = Tk()
canvas = Canvas(master, 
                width=canvas_width, 
                height=canvas_height)
canvas.pack()
img = PhotoImage(file="rocks.ppm")
canvas.create_image(20,20, anchor=NW, image=img)
mainloop()
Okno, vytvořené tímto skriptem, vypadá takto:
Cvičení
Napište funkci, která vytvoří čtverečkovaný rastr v plátně. Volání této funkce bude mít tvar: checkered(canvas, line_distance). Line_distance je vzdálenost horizontálních a vertikálních přímek.
Solution
from tkinter import *
def checkered(canvas, line_distance):
    # vertical lines at an interval of "line_distance" pixel
    for x in range(line_distance, canvas_width, line_distance):
        canvas.create_line(x, 0, x, canvas_height, fill="#476042")
    # horizontal lines at an interval of "line_distance"  pixel
    for y in range(line_distance, canvas_height, line_distance):
        canvas.create_line(0, y, canvas_width, y, fill="#476042")
master = Tk()
canvas_width = 200
canvas_height = 100 
w = Canvas(master, 
           width=canvas_width,
           height=canvas_height)
w.pack()
checkered(w,10)
mainloop()
Výsledek skriptu vypadá následovně: