【问题标题】:How to delete and recreate a canvas ? (TKINTER / CANVAS )如何删除和重新创建画布? (TKINTER / 帆布)
【发布时间】:2020-11-24 20:07:40
【问题描述】:

我已经在网上搜索了几个小时如何删除并接下来在 Tkinter 上重新创建“画布”。

首先是我的代码:

import tkinter as tk
import time
import numpy as np
m = 100
matrice = np.zeros((m,m))
matrice[10][10] = 1

root = tk.Tk()
root.title("Test")
root.geometry('1200x800')
canvas = tk.Canvas(width = 700 , height = 700)

def trace(m) :
    global canvas
    m2 = int(700/m)
    canvas.destroy()
    canvas = tk.Canvas(width = 700 , height = 700)
    for i in range(0,m) :
        for j in range(0,m) : 
            x = m2*i
            y = m2*j
            canvas.create_rectangle(x , y , m2+x , m2+y,outline = 'grey' , width = 1)

def affiche_points(m,matrice) :
    global canvas
    m2 = int(700/m)
    for i in range(m):
        for j in range(m):
            if matrice[i][j] == 1 :
                x = m2*i
                y = m2*j
                canvas.create_rectangle(x , y , m2+x , m2+y , fill = 'black')


def actualisation(m,matrice) :
    global canvas
    trace(m)
    affiche_points(m,matrice)
    canvas.pack()


actualisation(m,matrice)

for i in range(0,20) :

    matrice = np.zeros((m,m)) 
    matrice[i][10] = 1
    actualisation(m,matrice)
    time.sleep(0.5) 



root.mainloop()

我只想创建一个网格,当矩阵中的元素发生变化时,网格也会发生变化(0 = 白色,1 = 黑色) 就我而言,我使用

canvas.destroy()

清除窗口

然后我用 time.sleep() 等待 0.5 秒,直到我显示来自矩阵的新图像

我的问题是我看不到实现 :(

我只看到最后一帧! 不知道是canvas.pack()之类的不能刷新。

注意:这是对更大计划的简化!

NB 2:对不起,我的英语很奇怪,我是法国人,你知道...

谢谢你

【问题讨论】:

  • 你不需要破坏画布,使用canvas.delete('all')清除画布。同样time.sleep() 会阻塞应用程序,所以mainloop() 在for 循环结束之前不会被执行来更新画布。在trace() 的末尾使用canvas.update()affiche_points() 函数来强制更新。
  • 谢谢它真的很好用!
  • 我的主要问题是在每次刷新之间添加时间!但我找到了 root.after(time in ms)

标签: python tkinter canvas


【解决方案1】:

解释

这个问题显然有两个部分:

  1. 如何为当前画布上的每个项目获取可保存的细节结构(手动记录我们添加和删除的项目确实很痛苦,因此我们将忽略此作为解决方案)
  2. 如何从这个保存的状态重建项目

对于第一部分的问题,我相信还有另外三个部分需要考虑*,分别是:

  1. 如何获取画布对象的类型(线、矩形等)。事实证明这相当简单,因为我们可以使用 Canvas.type 方法。
  2. 如何获取项目的坐标。这不是很明显,需要一点 Tcl 知识才能得到解决方案。解决方案是使用Canvas.coords,tkinter 文档没有解释的是,如果在没有任何坐标的情况下调用此方法(仅提供item),它将返回给定项目的当前坐标(而不是更改它们)。
  3. 如何获取项目的选项及其值。和上面一样,解决这个问题需要对 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()

编辑

依赖另一个 tkinter 对象(Canvas.create_imageCanvas.create_window)的 Canvas 对象如果在不同的实例中运行(即保存然后恢复的详细信息)将无法正确恢复,因为这些对象需要使用相同的 Tcl 名称重新初始化.为此,可能需要读取相关 kwargs 的值,然后使用 Misc.nametowidgetMisc.config 的组合来获取所需信息。

【讨论】:

  • 但我不明白你回答中的所有内容,确实我是 tkinter 的新手!在您的代码中,我不了解带有 objs 的部分。我主要担心问题的第二部分。我不知道我是否真的很清楚,或者我只是不明白答案。在我的代码中,一切似乎都有效。唯一的问题是每次我想看到“下一帧”(当我重新创建网格并重新着色框时)它只显示最后一个“帧”
  • 我终于找到了一个简单的解决方案来解决我的问题(在评论中查看我的问题)!但你的回答最能帮助我理解 tkinter 的工作原理;)
  • resume 部分不适用于图像 (create_image()) 或窗口 (create_window()) 项。
  • @acw1668,感谢您指出这一点(请参阅我的编辑)。亚历山大·莫雷拉(Alexandre Moreira),很抱歉,因为我不明白这个问题。尽管它没有回答你的问题,但我会将我的答案留给那些在谷歌上搜索并偶然发现它的人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-19
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
相关资源
最近更新 更多