Работа с холстом Canvas в библиотеке tkinter

Раздел: Библиотеки -> Графический интерфейс

Холст Canvas в tkinter: основы и варианты использования

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

Создание холста происходит через конструктор Canvas(parent, width, height, bg, ...). После создания холст упаковывается в окно методами pack(), grid() или place().


import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=300, bg='white')
canvas.pack()
root.mainloop()

Python tkinter canvas (холст canvas в tkinter)

Холст поддерживает рисование примитивов: линий, прямоугольников, овалов, дуг, многоугольников, текста. Каждый графический объект создаётся соответствующим методом холста (create_line, create_rectangle, create_oval и т.д.) и возвращает уникальный идентификатор (item ID).


canvas.create_line(10, 10, 200, 100, fill='blue', width=3)
canvas.create_rectangle(50, 150, 150, 250, outline='red', fill='yellow')
canvas.create_oval(250, 50, 350, 150, fill='green')

Python tkinter frame (фрейм frame в tkinter)

Варианты решений для типовых задач

Как нарисовать линию со стрелками на концах?

Используется параметр arrow со значениями 'first', 'last' или 'both'. Дополнительно можно задать форму стрелки через arrowshape.


canvas.create_line(20, 20, 200, 100, arrow='both', arrowshape=(8,10,4), width=2)

Python tkinter messagebox (messagebox в tkinter)

Проблема: стрелка может быть слишком большой или маленькой. Решение - подбирать кортеж в arrowshape (первые два числа задают длину и ширину, третье - расстояние от острия до линии).

Как сделать закруглённый прямоугольник?

Прямоугольник с закруглёнными углами рисуется через метод create_rectangle с параметром smooth=True. Однако это даёт сглаживание углов, но не полное скругление. Для точного скругления используют дуги.


canvas.create_rectangle(50, 50, 150, 150, smooth=True, fill='lightblue')

Tkinter python ввод (ввод данных в tkinter)

Ошибка: smooth=True без указания степени сглаживания может давать неожиданные формы. Рекомендуется комбинировать с параметром splinesteps (например, splinesteps=20).

Как разместить изображение на холсте?

Изображение (PhotoImage или PIL Image) загружается и помещается методом create_image. Координаты указывают центр изображения.


from tkinter import PhotoImage

img = PhotoImage(file='picture.png')
canvas.create_image(200, 150, image=img)

Python tkinter виджет (виджеты tkinter)

Типичная ошибка: ссылка на объект PhotoImage не сохраняется - изображение не отображается. Необходимо хранить его в переменной, например, как атрибут класса или глобальную переменную.

Как обрабатывать клик мыши по холсту?

К холсту привязываются события: <Button-1> (левая кнопка), <Button-3> (правая), <Motion> (движение). Обработчик получает объект события с координатами x, y.


def on_click(event):
    print(f'Клик по ({event.x},{event.y})')

canvas.bind('<Button-1>', on_click)

Python file select (диалог выбора файла в python (tkinter.filedialog))

Проблема: координаты могут быть смещены, если холст свёрнут или есть отступы. Решение - использовать event.x_root и event.y_root или задать точный anchor.

Как создать анимацию движения объекта?

Анимация строится на периодическом изменении координат объекта с помощью canvas.move() или canvas.coords(), вызываемых через after().


ball = canvas.create_oval(10, 10, 50, 50, fill='red')
dx, dy = 2, 2

def animate():
    global dx, dy
    canvas.move(ball, dx, dy)
    # проверка границ
    x1, y1, x2, y2 = canvas.coords(ball)
    if x2 > 400 or x1 < 0: dx = -dx
    if y2 > 300 or y1 < 0: dy = -dy
    canvas.after(10, animate)

animate()

Python tkinter игра (игра на tkinter)

Ошибка: анимация может тормозить из-за частых вызовов after. Решение - увеличить интервал (например 20-30 мс).

Как очистить холст или удалить объект?

Для удаления всех объектов используется canvas.delete('all'). Для удаления конкретного объекта - его ID или тег.


item = canvas.create_rectangle(0,0,50,50)
canvas.delete(item)

Проблема: после удаления объекта его ID становится недействительным - попытка использовать его в других методах вызовет ошибку. Хранить ID следует в переменной.

Цели и случаи использования

Canvas применяется везде, где нужна двумерная графика: построение графиков функций, создание простых игр (арканоид, змейка), рисование схем, интерактивные образовательные приложения. Каждый вариант решает конкретную задачу: рисование, обработка событий, анимация, работа с изображениями.

- Python tkinter bind (метод bind() в tkinter)
- Python tkinter image (работа с изображениями в tkinter)
- Python tkinter списки (списки в tkinter)

Расширенные примеры работы с Canvas

Пример 1: Рисование графика функции

Построим синусоиду. Координаты масштабируем относительно размеров холста.

Пример

import math, tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=300, bg='white')
canvas.pack()

# оси
canvas.create_line(50, 150, 450, 150, arrow='last')
canvas.create_line(50, 250, 50, 50, arrow='last')

# график
points = []
for x in range(0, 400):
    # отображение x от 0 до 4π
    fx = 0.01 * x  # масштаб
    y = 150 - 100 * math.sin(fx)
    points.append((x+50, y))

canvas.create_line(points, fill='blue', smooth=True)
root.mainloop()
(результат: окно с синусоидой и осями)

Пример 2: Интерактивный рисовальщик

Пользователь рисует линии, удерживая левую кнопку мыши.

Пример

import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=600, height=400, bg='white')
canvas.pack()

last = [None, None]

def start_draw(event):
    last[0] = event.x
    last[1] = event.y

def draw(event):
    if last[0] is not None:
        canvas.create_line(last[0], last[1], event.x, event.y, width=2)
        last[0] = event.x
        last[1] = event.y

def stop_draw(event):
    last[0] = None
    last[1] = None

canvas.bind('<Button-1>', start_draw)
canvas.bind('<B1-Motion>', draw)
canvas.bind('<ButtonRelease-1>', stop_draw)
root.mainloop()
(результат: окно, в котором можно рисовать линии)

Пример 3: Использование тегов для группировки объектов

Теги позволяют обращаться сразу к группе объектов (например, изменить цвет всех объектов одного типа).

Пример

import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=200, bg='white')
canvas.pack()

# создаём объекты с тегами
canvas.create_oval(20, 20, 80, 80, fill='red', tags=('circle', 'shape'))
canvas.create_rectangle(120, 20, 180, 80, fill='blue', tags=('rect', 'shape'))
canvas.create_rectangle(220, 20, 280, 80, fill='green', tags=('rect', 'shape'))

# изменить цвет всех прямоугольников
canvas.itemconfig('rect', fill='yellow')
# удалить все круги
canvas.delete('circle')
root.mainloop()
(результат: два прямоугольника жёлтого цвета, круг исчез)

Пример 4: Анимация движения нескольких объектов

Создадим три шара разного цвета, движущихся с разными скоростями.

Пример

import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=300, bg='black')
canvas.pack()

balls = []
colors = ['white', 'red', 'blue']
for i, col in enumerate(colors):
    y = 50 + i * 80
    ball = canvas.create_oval(10, y, 50, y+40, fill=col)
    balls.append({'id': ball, 'dx': 1+i, 'dy': 0})

def move_balls():
    for b in balls:
        canvas.move(b['id'], b['dx'], b['dy'])
        x1, _, x2, _ = canvas.coords(b['id'])
        if x2 > 500 or x1 < 0:
            b['dx'] = -b['dx']
    root.after(15, move_balls)

move_balls()
root.mainloop()
(результат: три шара движутся горизонтально, отражаясь от стенок)

Холст Canvas в tkinter - comments

En
Python tkinter canvas (python)