Геометрические примитивы графического элемента Canvas (холст) модуля Tkinter. Урок 12

Методическая разработка урока
Элективный курс: Модуль tkinter. Создание графического интерфейса пользователя с помощью языка программирования Python
Уровень: Программирование для начинающих

Canvas (холст) — это достаточно сложный объект библиотеки tkinter. Он позволяет располагать на самом себе другие объекты. Это могут быть как геометрические фигуры, узоры, вставленные изображения, так и другие виджеты (например, метки, кнопки, текстовые поля). И это еще не все. Отображенные на холсте объекты можно изменять и перемещать (при желании) в процессе выполнения скрипта. Учитывая все это, canvas находит широкое применение при создании GUI-приложений c использованием tkinter (создание рисунков, оформление других виджет, реализация функций графических редакторов, программируемая анимация и др.).

В данном уроке будет рассмотрено создание на холсте графических примитивов (линии, прямоугольника, многоугольника, дуги (сектора), эллипса) и текста.

Для того, чтобы создать объект-холст необходимо вызвать соответствующий класс модуля tkinter и установить некоторые значения свойств (опций). Например:

canv = Canvas(root,width=500,height=500,bg="lightblue",
          cursor="pencil")

Далее с помощью любого менеджера геометрии разместить на главном окне.

Перед тем как создавать геометрические фигуры на холсте следует разобраться с координатами и единицами измерения расстояния. Нулевая точка (0,0) для объекта Canvas располагается в верхнем левом углу. Единицы измерения пиксели (точки экрана). Для «ориентации в пространстве» объекта Canvas рассмотрите рисунок ниже. У любой точки первое число — это расстояние от нулевого значения по оси X, второе — по оси Y.

Координатная ось с точкой отсчета вверху слева

Чтобы нарисовать линию на холсте следует к объекту (в нашем случае, canv) применить метод create_line.

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

Четыре числа — это пары координат начала и конца линии, т.е в примере первая линия начинается из точки (200,50), а заканчивается в точке (300,50). Вторая линия начинается в точке (0,0), заканчивается — в (100,100). Свойство fill позволяет задать цвет линии отличный от черного, а arrow – установить стрелку (в конце, начале или по обоим концам линии).

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

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

Опция outline определяет цвет границы прямоугольника.

Чтобы создать произвольный многоугольник, требуется задать пары координат для каждой его точки.

canv.create_polygon([250,100],[200,150],[300,150],fill="yellow") 

Квадратные скобки при задании координат используются для удобочитаемости (их можно не использовать). Свойство smooth задает сглаживание.

canv.create_polygon([250,100],[200,150],[300,150],fill="yellow")
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")

Более сложные для понимания фигуры получаются при использовании метода create_arc. В зависимости от значения опции style можно получить сектор (по умолчанию), сегмент (CHORD) или дугу (ARC). Координаты по-прежнему задают прямоугольник, в который вписана окружность, из которой «вырезают» сектор, сегмент или дугу. От опций start и extent зависит угол фигуры.

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) 

Последний метод объекта canvas, который будет рассмотрен в этом уроке — это метод создающий текстовую надпись.

canv.create_text(20,330,text="Опыты с графическими примитивами\nна холсте",
          font="Verdana 12",anchor="w",justify=CENTER,fill="red") 

Трудность здесь может возникнуть с пониманием опции anchor (якорь). По умолчанию в заданной координате располагается центр текстовой надписи. Чтобы изменить это и, например, разместить по указанной координате левую границу текста, используется якорь со значением w (от англ. west – запад). Другие значения: n, ne, e, se, s, sw, w, nw. Если букв, задающих сторону привязки две, то вторая определяет вертикальную привязку (вверх или вниз «уйдет» текст от координаты). Свойство justify определяет лишь выравнивание текста относительно себя самого.

В конце следует отметить, что часто требуется «нарисовать» на холсте какие-либо повторяющиеся элементы. Для того, чтобы не загружать код, используют циклы. Например, так:

x=10
while x < 450:
     canv.create_rectangle(x,400,x+50,450)
     x = x + 60 

Если вы напишите код приведенный в данном уроке (предварительно совершив импорт модуля Tkinter и создание главного окна, а также не забыв расположить на окне холст, и в конце «сделать» mainloop), то при его выполнении увидите такую картину:

Работа с виджетом Canvas в Tkinter

Практическая работа

Запрограммируйте следующие изображения на виджетах-холстах:

Работа с графикой в Tkinter

Можно ли, и если да, то как:

Можно ли, и если да, то как: изображать отрезки, заданные уравнениями. Достаточно ли tkinter,или нужно что-то ещё ?

Примерное решение

Примерное решение практического задания в моём исполнении

#Первое задание(файл 1.py)
from tkinter import *
 
root=Tk()
 
f='Arial 18'
w,h=400,500
canv=Canvas(root,width=w,height=h,bg='white')
 
#рисуем сетку
y=100
while y<h:
        canv.create_line(0,y,w,y)
        y+=100
 
x=100
while x<w:
        canv.create_line(x,0,x,h)
        x+=100
 
#шапка таблици
x,y=50,50
z=('X','Y','X and Y','X or Y')
for t in z:
        canv.create_text(x,y,text=t,font=f)
        x+=100
 
#заполняем таблицу
i=0
X=(0,0,1,1)
Y=(0,1,0,1)
x,y=50,150
while i<4:
        canv.create_text(x,y,text=X[i],font=f)
        canv.create_text(x+100,y,text=Y[i],font=f)
        canv.create_text(x+200,y,text=X[i] and Y[i],font=f)
        canv.create_text(x+300,y,text=X[i] or Y[i],font=f)
        y+=100
        i+=1
 
canv.pack()
 
root.mainloop()
 
 
#Второе задание(файл 2.py)
from tkinter import *
 
root=Tk()
 
f='Arial-16'
w=600
h=400
canv=Canvas(root,width=w,height=h,bg='#FFFFFF')
 
canv.create_rectangle(1,1,w,h,outline='blue',width=10)
 
canv.create_text(w-100,h-80,text='P - main program',font=f)
canv.create_text(w-100,h-60,text='F1 - function 1',font=f)
canv.create_text(w-100,h-40,text='F2 - function 2',font=f)
 
canv.create_text(110,40,text='F1',font=f)
canv.create_rectangle(100,50,120,130,fill='#90EE90',width=3)
 
canv.create_text(260,40,text='P',font=f)
i=0
while i<11:
        canv.create_rectangle(250,50+i*20,270,70+i*20,fill='#FFFF00',width=2)
        i+=1
 
canv.create_text(410,40,text='F2',font=f)
canv.create_rectangle([400,50],[420,190],fill='#ADD8E6',width=3)
 
canv.create_line([250,220],[60,220],width=2)
canv.create_line([60,220],[60,60],width=2)
canv.create_line([60,60],[100,60],width=2,arrow=LAST)
 
canv.create_line([250,80],[160,80],width=2)
canv.create_line([160,80],[160,60],width=2)
canv.create_line([160,60],[120,60],width=2,arrow=LAST)
 
canv.create_line([270,120],[360,120],width=2)
canv.create_line([360,120],[360,60],width=2)
canv.create_line([360,60],[400,60],width=2,arrow=LAST)
 
canv.pack()
root.mainloop()

Впринципе все понятно, вот

Впринципе все понятно, вот только код массивный очень!!! Как сделать его меньше? Задавал y! Задавал еще переменные, но не получилось вывести правильный код - математика страдает ). Спасибо ВАМ за уроки - иду с самого начала! Перелапатил много всего - у ВАС все сжато и очень "восприибельно". Надеюсь, что на этом ВАШИ обучающие материалы не закончатся! К учителю, так сказать, привыкаешь ;-)

from tkinter import *
root=Tk()
 
canv=Canvas(root, height=500, width=320, bg="grey")
x=0
while x < 320:
    canv.create_rectangle(x,0,x+80,100, fill="white", outline="blue")
    x=x+80
 
x=0
while x != 560:
    canv.create_rectangle(x,100,x+80,200, fill="white", outline="blue")
    x=x+80
 
x=0
while x != 560:
    canv.create_rectangle(x,200,x+80,300, fill="white", outline="blue")
    x=x+80
 
x=0
while x != 560:
    canv.create_rectangle(x,300,x+80,400, fill="white", outline="blue")
    x=x+80
 
x=0
while x != 560:
    canv.create_rectangle(x,400,x+80,500, fill="white", outline="blue")
    x=x+80
 
x=0
while x != 560:
    canv.create_rectangle(x,500,x+80,600, fill="white", outline="blue")
    x=x+80
 
canv.create_text(40,50,text="X", font="Arial 15")
canv.create_text(120,50,text="Y", font="Arial 15")
canv.create_text(200,50,text="XandY", font="Arial 15")
canv.create_text(280,50,text="XorY", font="Arial 15")
canv.create_text(40,150,text="0", font="Arial 15")
canv.create_text(40,250,text="0", font="Arial 15")
canv.create_text(40,350,text="1", font="Arial 15")
canv.create_text(40,450,text="1", font="Arial 15")
canv.create_text(120,150,text="0", font="Arial 15")
canv.create_text(200,150,text="0", font="Arial 15")
canv.create_text(280,150,text="0", font="Arial 15")
canv.create_text(120,250,text="1", font="Arial 15")
canv.create_text(200,250,text="0", font="Arial 15")
canv.create_text(280,250,text="1", font="Arial 15")
canv.create_text(120,350,text="0", font="Arial 15")
canv.create_text(200,350,text="0", font="Arial 15")
canv.create_text(280,350,text="1", font="Arial 15")
canv.create_text(120,450,text="1", font="Arial 15")
canv.create_text(200,450,text="1", font="Arial 15")
canv.create_text(280,450,text="1", font="Arial 15")
canv.pack()
root.mainloop()

Прорисовка прямоугольников

Прорисовка прямоугольников сокращается до следующего цикла:

y = 0
while y < 600:
    x=0
    while x < 320:
        canv.create_rectangle(x,y,x+80,y+100, fill="white", outline="blue")
        x=x+80
    y = y + 100

Можно было бы вместо этого нарисовать горизонтальные и вертикальные линии. Однако тогда пришлось бы использовать два независимых цикла. Но поскольку линий мало, то короче было бы вообще без цикла.

Зациклить вывод текста для данного примера уже сложнее, т.к. меняются не только координаты, но и значение свойства text. Можно значения text предварительно поместить в список, а потом извлекать по меняющемуся индексу.

value = ['X','Y','X and Y','X or Y',0,0,0,0,0,1,0,1,1,0,0,1,1,1,1,1]
i = 0
y = 50
while i < 20:
    x = 40
    j = 0
    while j < 4:
        canv.create_text(x,y,text=value[i], font="Arial 15")
        x += 80
        j += 1
        i += 1
    y += 100

Спасибо!

Спасибо!

Редкий мануал написаный

Редкий мануал написаный человеческим языком, грамотно и доступн. !Нижайшая благодарность Автору! Надеюсь на дополнение этого раздела.

Да, еще побольше бы уроков по

Да, еще побольше бы уроков по питону. Лично мне эта тема очень актуальна. И класно оформили сайт! Спасибо автору!

Ещё надо отобразить сам

Ещё надо отобразить сам холст.