如何复制tkinter canvas中嵌入的龟框内容

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何复制tkinter canvas中嵌入的龟框内容相关的知识,希望对你有一定的参考价值。

我试图保存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 fileslibcopy.py", line 173, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "C:python fileslibcopy.py", line 295, in _reconstruct
    state = deepcopy(state, memo)
  File "C:python fileslibcopy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "C:python fileslibcopy.py", line 235, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "C:python fileslibcopy.py", line 173, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "C:python fileslibcopy.py", line 295, in _reconstruct
    state = deepcopy(state, memo)
  File "C:python fileslibcopy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "C:python fileslibcopy.py", line 235, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "C:python fileslibcopy.py", line 173, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "C:python fileslibcopy.py", line 280, in _reconstruct
    y = callable(*args)
  File "C:python fileslibcopyreg.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小部件:

screenshot of program running

这是演示代码,演示如何遍历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}
{}'.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()

以上是关于如何复制tkinter canvas中嵌入的龟框内容的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Canvas 上的 Tkinter 中打开 PIL 图像

如何在 tkinter Canvas 中检测点击对象的标签?

如何使用 tkinter Canvas 小部件制作按钮?

使用带有 pylab/matplotlib 嵌入的 Tkinter 播放、暂停、停止功能的彩色绘图动画:无法更新图形/画布?

如何利用Tkinter中Canvas绘制曲线图,请教高手

如何将 python tkinter 窗口嵌入浏览器?