Языки программирования

Библиотека Tkinter: Графические примитивы

В этой статье мы познакомимся с графикой в библиотеке Tkinter. Начнем с графических примитив и в других статьях будем создавать сложные графические программы.

При работе с двухмерной графикой базовым понятием является холст.

Canvas (холст) — это достаточно сложный объект библиотеки tkinter. Он помогает располагать геометрические фигуры, узоры вставленные изображения и другие виджеты (например, метки, кнопки, текстовые поля).

При создании экземпляра Canvas необходимо указать его ширину и высоту. При размещении геометрических примитивов и других объектов указываются их координаты на холсте. Точкой отсчета является верхний левый угол.

Для того чтобы создать объект-холст необходимо вызвать соответствующий класс модуля tkinter и установить некоторые значения свойств. Например:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

canv = Canvas(root, width=500, height=400, bg='lightgray', cursor='pencil')

canv.pack()
root.mainloop()
В этом примере мы создаем холст с размером 500х400 пикселей и светло-серым фоном.

Перед тем как создавать геометрические фигуры на холсте следует разобраться с координатами и единицами измерения на холсте. Нулевая точка (0,0) для объекта Canvas располагается в верхнем левом углу.

Единицы измерения пиксели (точки экрана). У любой точки первое число — это расстояние от нулевого значения по оси X, второе — по оси Y.

Чтобы нарисовать линию на холсте следует к объекту применить метод create_line. Пример:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

canv = Canvas(root, width=500, height=400, bg='lightgray', cursor='pencil')

canv.create_line(200,50,300,50, width=3, fill="blue")
canv.create_line(0,0,100,100, width=2, arrow=LAST)

canv.pack()
root.mainloop()
Будет выведено:
Четыре числа — это пары координат начала и конца линии. Свойство fill позволяет задавать цвет линии отличный от черного, а arrow — установить стрелку (в конце, начале или по обоим концам линии).

Метод create_rectangle создает прямоугольник. Аналогично линии в скобках первыми аргументами прописываются четыре числа. Первые две координаты обозначают верхний левый угол прямоугольника, вторые — правый нижний.

Рассмотрим пример:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

canv = Canvas(root, width=500, height=400, bg='lightgray', cursor='pencil')

x = 50
y = 300
canv.create_rectangle(x,y,x+80,y+50, fill="white", outline="blue")

canv.pack()
root.mainloop()
Опция outline определяет цвет границы прямоугольника.

Будет выведено:
Чтобы создать произвольный многоугольник, требуется задать пары координат для каждой его точки. В примере мы рассмотрим другой подход. Он может быть полезен, если начальные координаты объекта могут изменяться, а его размер строго регламентирован:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

canv = Canvas(root, width=500, height=400, bg='lightgray', cursor='pencil')

canv.create_polygon([250,110],[200,150],[300,150], fill="red")

canv.pack()
root.mainloop()
Будет выведено:
Квадратные скобки при задании координат используются для удобочитаемости (их можно не использовать). Свойство smooth задает сглаживание:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

canv = Canvas(root, width=500, height=400, bg='lightgray', cursor='pencil')

canv.create_polygon([250,110],[200,150],[300,150], fill="red")
canv.create_polygon([300,80],[400,80],[450,75],[450,200],[300,180],[330,160],outline="white", smooth=1)

canv.pack()
root.mainloop()
Выведет:
При создании эллипса задаются координаты гипотетического прямоугольника, описывающего данный эллипс:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

canv = Canvas(root, width=500, height=400, bg='lightgray', cursor='pencil')

canv.create_polygon([250,110],[200,150],[300,150], fill="red")
canv.create_polygon([300,80],[400,80],[450,75],[450,200],[300,180],[330,160],outline="white", smooth=1)
canv.create_oval([20,200],[150,300], fill="gray50") # создаем эллипс

canv.pack()
root.mainloop()
Выведет:
Более сложные для понимания фигуры получаются при использовании метода create_arc.

В зависимости от значения опции style можно получить сектор (по умолчанию), сегмент (CHORD) или дугу (ARC). От опций start и extent зависит угол фигуры. Метод create.text создает текстовую надпись. Пример:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

canv = Canvas(root, width=500, height=400, bg='lightgray', cursor='pencil')

canv.create_arc([160,230], [230,330], start=0, extent=140, fill="lightgreen")
canv.create_arc([250,230], [320,330], start=0, extent=140, style=CHORD, fill="green")
canv.create_arc([340,230], [410,330], start=0, extent=140, style=ARC, outline="darkgreen", width=2)
canv.create_text(20,330, text="Графические примитивы", font="Verdana 14", anchor="w", justify=CENTER, fill="red")

canv.pack()
root.mainloop()
Будет выведено:
Если что часто требуется «нарисовать» на холсте какие-либо повторяющиеся элементы. Для того, чтобы не загружать код, используют циклы. Например, так:
x=10
   while x < 450:
   canv.create_rectangle(x,400,x+50,450)
   x = x + 60

Обращение к уже существующим графическим примитивам

Чтобы можно было изменять свойства уже существующих объектов холста (например, геометрических фигур) в tkinter используют идентификаторы и теги, которые затем передаются другим методам.
У любого объекта может быть как идентификатор, так и тег. Использование идентификаторов и тегов немного различается.
Рассмотрим несколько методов изменения уже существующих объектов с использованием при этом идентификаторов. Для начала создадим холст и три объекта на нем.
При создании объекты "возвращают" свои идентификаторы, которые можно связать с переменными (oval, rect и trial в примере ниже) и потом использовать их для обращения к конкретному объекту:
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

c = Canvas(width=460,height=460,bg='grey80')
c.pack()
oval = c.create_oval(30,10,130,80)
rect = c.create_rectangle(180,10,280,80)
trian = c.create_polygon(330,80,380,10,430,80, fill='grey80', outline="black")

root.mainloop()
Будет выведено:
Далее можно использовать методы-"модификаторы" указывая в качестве первого аргумента идентификатор объекта. Метод move перемещает объект по оси X и Y на расстояние указанное в качестве второго и третьего аргументов.

Следует понимать, что это не координаты, а смещение, т.е. в примере ниже прямоугольник опустится вниз на 150 пикселей. Метод itemconfig изменяет указанные свойства объектов, coords изменяет координаты (им можно менять и размер объекта).
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

c = Canvas(width=460,height=460,bg='grey80')
c.pack()
oval = c.create_oval(30,10,130,80)
rect = c.create_rectangle(180,10,280,80)
trian = c.create_polygon(330,80,380,10,430,80, fill='grey80', outline="black")

c.move(rect,0,150)
c.itemconfig(trian,outline="red",width=3)
c.coords(oval,300,200,450,450)

root.mainloop()
Метод tag_bind позволяет привязать событие (например, щелчок кнопкой мыши) к определенному объекту.

Таким образом, можно реализовать обращение к различным областям холста с помощью одного и того же события. Пример ниже это наглядно иллюстрирует: изменения на холсте зависят от того, где произведен щелчок мышью.
from tkinter import *
    
root = Tk()
root.title("Графические примитивы")
root.minsize(width=500, height=400)

c = Canvas(width=460,height=100,bg='grey80')
c.pack()

oval = c.create_oval(30,10,130,80,fill="orange")
c.create_rectangle(180,10,280,80,tag="rect",fill="lightgreen")
trian = c.create_polygon(330,80,380,10,430,80,fill='white',outline="black")

def oval_func(event):
 c.delete(oval)

c.create_text(30,10,text="Здесь был круг",anchor="w")

def rect_func(event):
 c.delete("rect")

c.create_text(180,10,text="Здесь был\nпрямоугольник",anchor="nw")

def triangle(event):
 c.create_polygon(350,70,380,20,410,70,fill='yellow',outline="black")

c.tag_bind(oval,'<Button-1>',oval_func)
c.tag_bind("rect",'<Button-1>',rect_func)
c.tag_bind(trian,'<Button-1>',triangle)

mainloop()
Будет выведено:
Библиотека Tkinter