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ě: