如何复制嵌入在 tkinter 中的 turtle frame 的内容 canvas

How to copy contents of turtle frame embedded in tkinter canvas

我正在尝试保存 tkinter canvas 的当前状态以便稍后显示。这是我尝试使用 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()

有谁知道如何复制屏幕,然后再添加到其他地方?

你不能为所欲为。小部件不是纯粹的 python 对象。他们的大部分状态都在嵌入式 tcl 解释器中。您根本无法像这样复制 tkinter 小部件。

简而言之,无法复制 tkinter 小部件。您可以做的最好的事情是使用 configure 方法获取小部件的所有配置选项,然后使用相同的选项创建一个新的小部件。即使这样,它也不会存储内部状态,例如 canvas 上的绘图、文本小部件中的文本等

无法复制小部件,但是如果您同时创建了一个相同的小部件,但没有调用几何管理器,则可以稍后将其添加到屏幕:

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 来节省时间:

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()

这似乎可以完成您想要的事情。这不是一个完整的示例,而只是演示了一种实现复制目标的方法。

你的问题没有任何代码实际在 Canvas 上绘制一些东西,所以我从 tutorial 那里借用了一些我发现的使用 tkinter 的代码,以便拥有a Canvas 上面有一些小部件,用于说明目的。它生成一个 window 看起来像这样,它有一个 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')}