Объяснение
Очевидно, что этот вопрос состоит из двух частей:
- Как получить сохраняемую структуру деталей для каждого элемента, находящегося в данный момент на холсте (ведение журнала вручную какие элементы мы добавляем и удаляем, это настоящая проблема, поэтому мы проигнорируем это как решение)
- Как восстановить элементы из этого сохраненного состояния
Для первой части проблема, я считаю, что есть еще три части, которые необходимо рассмотреть *, а именно:
- Как получить тип объекта холста (линия, прямоугольник и т. д. c.) . Это оказывается довольно просто, так как есть метод
Canvas.type
, который мы можем использовать. - Как получить координаты элемента. Это не так очевидно и требует некоторых знаний Tcl, чтобы получить решение. Решение состоит в том, чтобы использовать
Canvas.coords
, а документация tkinter не объясняет, что если этот метод вызывается без каких-либо координат (предоставляется только item
), он вернет текущие координаты данный элемент (а не изменять их). - Как получить параметры и их значения для элемента. Как и выше, решение для этого требует небольшого понимания Tcl. Решение состоит в том, чтобы использовать
Canvas.itemconfig
без каких-либо аргументов, кроме item
(как указано выше), и это вернет словарь, содержащий все допустимые параметры для этого типа объекта холста и (среди прочего) текущее значение для этой опции.
Вторая часть проблемы оказалась намного проще, поскольку каждый из методов Canvas.create_*
просто вызывает скрытый метод Canvas._create
с координатами, kwargs и что самое интересное, тип объекта в виде строки. Например, вызов из Canvas.create_arc(*args, **kw)
будет Canvas._create('arc', args, kw)
, что легко увидеть в tkinter source (ссылка ведет на то, что было последним blob-файлом на момент написания). Следовательно, если мы выполнили часть поиска правильно, эту часть будет очень просто реализовать.
* Если я что-то упустил, оставьте комментарий, я постараюсь исправить это.
Код
(для тех из нас, кому лень читать объяснение!)
Вот моя реализация приведенного выше объяснения:
import tkinter as tk
root = tk.Tk()
root.title("Canvas resume demo")
c = tk.Canvas(root, width=400, height=400)
# Create your canvas objects with some random coords and kwargs
c.create_rectangle(0, 0, 100, 100, fill="red", width=3)
c.create_line(0, 0, 100, 100)
c.create_polygon(90, 100, 100, 90, 100, 100, fill="blue")
# Items can also be deleted
c.delete(c.create_line(100, 100, 200, 200))
# Save the details into 'objs' (which can be pickle or json dumped)
objs = [(c.type(item),
c.coords(item),
{i: j[-1] for i, j in c.itemconfig(item).items()}) \
for item in c.find_all()]
# Create a completely new canvas
c.destroy()
c = tk.Canvas(root, width=400, height=400)
c.pack()
# Resume from 'objs'
for item in objs:
c._create(*item)
root.mainloop()
РЕДАКТИРОВАТЬ
Объекты Canvas, которые полагаются на другой объект tkinter (Canvas.create_image
и Canvas.create_window
), не будут правильно возобновлены при запуске в другом экземпляре (т.е. сохраненные данные а затем возобновить), так как эти объекты нужно будет повторно инициализировать с тем же именем Tcl. Для этого, вероятно, потребуется прочитать значение для соответствующих kwargs, а затем использовать комбинацию Misc.nametowidget
и Misc.config
, чтобы получить необходимую информацию.