Python Tkinter刷新画布
您好,我在python中有一个元组,其颜色与画布中由以下词典绘制的正方形相关:Python Tkinter刷新画布,python,canvas,tkinter,Python,Canvas,Tkinter,您好,我在python中有一个元组,其颜色与画布中由以下词典绘制的正方形相关: colour_mapping = {0: "red", 1: "green", 2: "blue" , 3:"purple"} 更具体地说,例如元组处的节点是: ((2, 3), (3, 3)) 这意味着应以这种方式绘制4个正方形: blue square purple square purple square purple square 然后它们的颜色应该根据元组中的下一个节点相应地改变 为此,
colour_mapping = {0: "red", 1: "green", 2: "blue" , 3:"purple"}
更具体地说,例如元组处的节点是:
((2, 3), (3, 3))
这意味着应以这种方式绘制4个正方形:
blue square purple square
purple square purple square
然后它们的颜色应该根据元组中的下一个节点相应地改变
为此,我迭代元组,并为每个元素在画布上绘制一个新矩形,然后调用time.sleep()
函数,以便用户有时间查看与以前状态的差异。
我的问题是,只有最后一个节点被正确渲染,而所有其他节点都没有显示。你能帮我吗
以下是我目前的代码:
self.parent.title("AlienTiles")
self.style = Style()
self.style.theme_use("default")
self.frame = Frame(self, relief=RAISED, borderwidth=1)
self.frame.pack(fill=BOTH, expand=1)
self.canvas = Canvas(self.frame)
self.canvas.pack(fill=BOTH, expand=1)
self.pack(fill=BOTH, expand=1)
for i in range(len(path)) : #the tuple is path
state = path[i].state
print state
time.sleep(1)
y_offset=10
for x in state:
start_x=40
start_y=10
i=1
x_offset=0
for y in x:
x0=(start_x*i)+x_offset
y0=(start_y*i)+y_offset
x1=x0+size
y1=y0+size
colour=colour_mapping[y]
print colour
self.canvas.create_rectangle(x0, y0, x1, y1, fill=colour)
x_offset=x_offset+size+10
y_offset=y_offset+size+10
总之,我尝试制作一个上面描述的动画。在每次循环中,是否有什么我认为不正确的地方或是需要刷新画布的地方?首先,我有点困惑((2,3)(3,3))为什么会得到绿色和蓝色的方块。你的颜色编码似乎表明它们是蓝色和紫色的,不是吗 其次,我不能完全确定我是否理解“然后它们的颜色应该根据元组中的下一个节点相应地改变”的语句。这是否意味着在某一点上你将通过((2,3)(3,3))并期望得到4个正方形,然后下一次通过((2,3)(3,3)(1,2))并期望得到6个蓝色正方形 第三,你的程序的输出是什么?似乎你有足够的打印语句,你应该能够找出问题所在 在没有完全理解程序的情况下进行猜测,我猜问题在于一个for循环没有迭代正确的值,这导致没有绘制所有的正方形。我猜是第一个:
for i in range(len(path)) :
但这确实是一个猜测,因为正如我所说,我不完全理解发生了什么。如果你能回答我的一些问题,我会尽力帮助你。抱歉,我没有更多帮助。画布刷新的唯一方法是让事件循环服务于“重画”事件。在您的循环中,您从未给事件循环更新的机会,因此您看不到任何更改 快速修复方法是调用
self.canvas.update\u idletasks
,但这只是一种黑客行为,不是一个合适的解决方案
制作动画的正确方法是使用事件循环进行迭代。您可以通过将要完成的工作放置在队列上来实现这一点——在本例中,是空闲事件队列。您可以使用after
命令将内容放置在此队列上
您应该做的是编写一个函数,对动画进行一次迭代。本质上,将while循环中的所有内容移动到函数中。然后,只要有工作要做,就安排不断调用该函数。您可以在该函数中的之后调用,也可以使用单独的函数控制动画
大致来说,解决方案如下所示:
def do_one_frame(self, ...):
# do whatever you need to draw one frame
if (there_is_more_work_to_be_done):
self.after(10, do_one_frame)
这将绘制动画的一帧,检查是否有任何新帧要绘制,然后安排在10毫秒内绘制下一帧。当然,可以将该值设置为任意值,以控制动画的速度
这个网站上有这种技术的工作实例。例如,请参见链接似乎是dead@rpax:不幸的是,有人决定我链接到的问题不应该只关闭,而应该删除。我不明白其中的道理。谢谢你让我知道。我已将链接替换为另一个链接。仅使用self.canvas.update\u idletasks
是否有任何不利之处?因为它以最小的努力出色地解决了我的问题。