我试图保存tkinter画布的当前状态以便稍后显示。这是我尝试使用deepcopy
的方法:
from tkinter import *
from copy import deepcopy
root=Tk()
cv=Canvas(root)
cv.pack()
cvcopy=deepcopy(cv)
mainloop()
然而,行cvcopy=deepcopy(cv)
创建错误:
Traceback (most recent call last):
File "C:/Users/Fred/Desktop/painting/mcve.py", line 6, in <module>
cvcopy=deepcopy(cv)
File "C:\python files\lib\copy.py", line 173, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "C:\python files\lib\copy.py", line 295, in _reconstruct
state = deepcopy(state, memo)
File "C:\python files\lib\copy.py", line 146, in deepcopy
y = copier(x, memo)
File "C:\python files\lib\copy.py", line 235, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "C:\python files\lib\copy.py", line 173, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "C:\python files\lib\copy.py", line 295, in _reconstruct
state = deepcopy(state, memo)
File "C:\python files\lib\copy.py", line 146, in deepcopy
y = copier(x, memo)
File "C:\python files\lib\copy.py", line 235, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "C:\python files\lib\copy.py", line 173, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "C:\python files\lib\copy.py", line 280, in _reconstruct
y = callable(*args)
File "C:\python files\lib\copyreg.py", line 88, in __newobj__
return cls.__new__(cls, *args)
TypeError: object.__new__(tkapp) is not safe, use tkapp.__new__()
因为显然你不能像这样创建一个新的小部件。这是我在turtle
屏幕上嵌入和绘制的代码:
cv = tkinter.Canvas(self.root,width=300,height=300)
cv.pack()
t = turtle.RawTurtle(cv)
s = t.getscreen()
def toggledown():
if t.isdown():
t.penup()
else:
t.pendown()
t.speed(0)
t.ondrag(t.goto)
s.onclick(t.goto)
s.onkey(toggledown, 'space')
s.listen()
有谁知道如何复制屏幕,并在其他地方再次添加?
这似乎可以实现你想要的东西。这不是一个完整的例子,而只是演示了一种实现复制目标的方法。
你的问题没有任何实际在Canvas
上绘制内容的代码,所以我借用tutorial借用了我发现的tkinter
,以便有一个带有几个小部件的Canvas
用于说明目的。它产生一个看起来像这样的窗口,它有一个Button
和一个只包含三个不同颜色的矩形小部件的Canvas
小部件:
这是演示代码,演示如何遍历Canvas
上当前的所有小部件:
from pprint import pprint, pformat
from tkinter import Button, Tk, Canvas, Frame, BOTH
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.master.title("Colours")
self.pack(fill=BOTH, expand=1)
button = Button(self, text="Copy", command=self.copy_canvas)
button.pack()
self.canvas = Canvas(self)
self.canvas.create_rectangle(30, 10, 120, 80,
outline="#fb0", fill="#fb0")
self.canvas.create_rectangle(150, 10, 240, 80,
outline="#f50", fill="#f50")
self.canvas.create_rectangle(270, 10, 370, 80,
outline="#05f", fill="#05f")
self.canvas.pack(fill=BOTH, expand=1)
def copy_canvas(self):
# Iterate through all the items in self.canvas and print each
# one's type and options (which could be used to recreate it).
for id in self.canvas.find_all():
item_type = self.canvas.type(id)
options = self.canvas.itemconfigure(id)
formatted_options = pformat(options, indent=4)
print('id: {}, type: {!r}\n{}'.format(
id, item_type, formatted_options))
def main():
root = Tk()
ex = Example()
root.geometry("400x100+300+300")
root.mainloop()
if __name__ == '__main__':
main()
这是按下复制按钮时打印的内容:
id: 1, type: 'rectangle'
{ 'activedash': ('activedash', '', '', '', ''),
'activefill': ('activefill', '', '', '', ''),
'activeoutline': ('activeoutline', '', '', '', ''),
'activeoutlinestipple': ('activeoutlinestipple', '', '', '', ''),
'activestipple': ('activestipple', '', '', '', ''),
'activewidth': ('activewidth', '', '', '0.0', '0.0'),
'dash': ('dash', '', '', '', ''),
'dashoffset': ('dashoffset', '', '', '0', '0'),
'disableddash': ('disableddash', '', '', '', ''),
'disabledfill': ('disabledfill', '', '', '', ''),
'disabledoutline': ('disabledoutline', '', '', '', ''),
'disabledoutlinestipple': ('disabledoutlinestipple', '', '', '', ''),
'disabledstipple': ('disabledstipple', '', '', '', ''),
'disabledwidth': ('disabledwidth', '', '', '0.0', '0'),
'fill': ('fill', '', '', '', '#fb0'),
'offset': ('offset', '', '', '0,0', '0,0'),
'outline': ('outline', '', '', 'black', '#fb0'),
'outlineoffset': ('outlineoffset', '', '', '0,0', '0,0'),
'outlinestipple': ('outlinestipple', '', '', '', ''),
'state': ('state', '', '', '', ''),
'stipple': ('stipple', '', '', '', ''),
'tags': ('tags', '', '', '', ''),
'width': ('width', '', '', '1.0', '1.0')}
id: 2, type: 'rectangle'
{ 'activedash': ('activedash', '', '', '', ''),
'activefill': ('activefill', '', '', '', ''),
'activeoutline': ('activeoutline', '', '', '', ''),
'activeoutlinestipple': ('activeoutlinestipple', '', '', '', ''),
'activestipple': ('activestipple', '', '', '', ''),
'activewidth': ('activewidth', '', '', '0.0', '0.0'),
'dash': ('dash', '', '', '', ''),
'dashoffset': ('dashoffset', '', '', '0', '0'),
'disableddash': ('disableddash', '', '', '', ''),
'disabledfill': ('disabledfill', '', '', '', ''),
'disabledoutline': ('disabledoutline', '', '', '', ''),
'disabledoutlinestipple': ('disabledoutlinestipple', '', '', '', ''),
'disabledstipple': ('disabledstipple', '', '', '', ''),
'disabledwidth': ('disabledwidth', '', '', '0.0', '0'),
'fill': ('fill', '', '', '', '#f50'),
'offset': ('offset', '', '', '0,0', '0,0'),
'outline': ('outline', '', '', 'black', '#f50'),
'outlineoffset': ('outlineoffset', '', '', '0,0', '0,0'),
'outlinestipple': ('outlinestipple', '', '', '', ''),
'state': ('state', '', '', '', ''),
'stipple': ('stipple', '', '', '', ''),
'tags': ('tags', '', '', '', ''),
'width': ('width', '', '', '1.0', '1.0')}
id: 3, type: 'rectangle'
{ 'activedash': ('activedash', '', '', '', ''),
'activefill': ('activefill', '', '', '', ''),
'activeoutline': ('activeoutline', '', '', '', ''),
'activeoutlinestipple': ('activeoutlinestipple', '', '', '', ''),
'activestipple': ('activestipple', '', '', '', ''),
'activewidth': ('activewidth', '', '', '0.0', '0.0'),
'dash': ('dash', '', '', '', ''),
'dashoffset': ('dashoffset', '', '', '0', '0'),
'disableddash': ('disableddash', '', '', '', ''),
'disabledfill': ('disabledfill', '', '', '', ''),
'disabledoutline': ('disabledoutline', '', '', '', ''),
'disabledoutlinestipple': ('disabledoutlinestipple', '', '', '', ''),
'disabledstipple': ('disabledstipple', '', '', '', ''),
'disabledwidth': ('disabledwidth', '', '', '0.0', '0'),
'fill': ('fill', '', '', '', '#05f'),
'offset': ('offset', '', '', '0,0', '0,0'),
'outline': ('outline', '', '', 'black', '#05f'),
'outlineoffset': ('outlineoffset', '', '', '0,0', '0,0'),
'outlinestipple': ('outlinestipple', '', '', '', ''),
'state': ('state', '', '', '', ''),
'stipple': ('stipple', '', '', '', ''),
'tags': ('tags', '', '', '', ''),
'width': ('width', '', '', '1.0', '1.0')}
你无法做你想做的事。小部件不是纯粹的python对象。他们的大多数状态都是嵌入式tcl解释器。你根本无法像这样制作tkinter小部件的副本。
简而言之,无法复制tkinter小部件。您可以做的最好的事情是使用configure
方法获取窗口小部件的所有配置选项,然后使用相同的选项创建一个新的窗口小部件。即便如此,它也不会存储画布上的图形等内部状态,文本窗口小部件中的文本等。
无法复制窗口小部件,但是如果您同时创建相同的窗口小部件,但未调用几何管理器,则可以稍后将其添加到屏幕:
from tkinter import *
root = Tk()
cv = Canvas(self.root, width=300, height=300)
cv.pack()
copy = Canvas(otherframe, width=300, height=300)
t = turtle.RawTurtle(cv)
s = t.getscreen()
ct = turtle.RawTurtle(copy)
cs = ct.getscreen()
def toggledown():
if t.isdown():
t.penup()
ct.penup() #no point testing twice since they're the same
else:
t.pendown()
ct.pendown()
def goto(x, y):
t.goto(x, y)
ct.goto(x, y)
Button(self.root, text='Copy', command=copy.pack).pack()
t.speed(0)
ct.speed(0)
t.ondrag(goto) #the copy will go to the same place
s.onclick(goto)
s.onkey(toggledown, 'space')
s.listen()
mainloop()
在这种情况下,您还可以通过为画布创建类来节省时间:
class Drawing(object):
def __init__(self, master, otherframe):
self.cv = Canvas(master, width=300, height=300)
self.cv.pack()
self.copy = Canvas(otherframe, width=300, height=300)
self.t.RawTurtle(self)
self.s = self.t.getscreen()
self.ct.RawTurtle(self)
self.cs = self.ct.getscreen()
self.ct.speed(0)
self.t.speed(0)
self.t.ondrag(self.goto) #the copy will go to the same place
self.s.onclick(self.goto)
self.s.onkey(self.toggledown, 'space')
self.s.listen()
def toggledown(self):
if self.t.isdown():
self.t.penup()
self.ct.penup()
else:
self.t.pendown()
self.ct.pendown()
def goto(self, x, y):
self.t.goto(x, y)
self.ct.goto(x, y)
def addCopy(self):
self.copy.pack()