在 tkinter 中重复创建和删除一个对象(例如矩形)
creating and deleting an object (e.g. rectangle) ager a time delay repeatedly in tkinter
我是 python 的新手。目前我的目标是编写一个程序,该程序必须在几秒钟后重复创建和删除对象(矩形、圆形等)。如果我在单独的函数中使用 .after 方法,我会收到错误消息:UnboundLocalError: local variable 'counter' 赋值前引用的时候,看自己的代码。或者,如果我把重复的代码放在程序的主要部分,它只显示最后的状态,而不是中间的状态(见代码中“”和“”之间的描述。我在网上搜索了一段时间但我无法解决。希望你能帮助我。
这是我的代码的简化版本(实际上我正在使用 rec's 列表),它显示了我的问题:
import tkinter as tk
def master_field(text):
""" work field (master) construction"""
master.geometry('500x500+0+0')
master.title(text)
def stop_button():
"""exit"""
b = tk.Button(master, text = 'Exit', width=2, command = master.destroy)
b.place(x = 50, y = 0, width = 100)
def built_canvas():
"""create a canvas"""
canvas=tk.Canvas(master, width = canvas_width, height = canvas_height, borderwidth = 1, bg='light grey', highlightthickness=0, highlightbackground="blue")
canvas.place(x = 0, y = 20)
return canvas
def update_canvas():
while counter<10:
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
counter +=1
master.after(500,update_canvas)
# MAIN
master = tk.Tk()
master_field('MY FIELD')
stop_button()
canvas_width = 200
canvas_height = 200
canvas = built_canvas()
cell_width = 10
x1 = 10
y1 = 10
x2 = x1+10
y2 = y1+10
rec = canvas.create_rectangle(x1,y1,x2,y2, width=0, fill="green")
counter = 0
master.after(500,update_canvas)
"""
# The code below only gives the final state
for i in range(1,10):
master.after(500)
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
"""
master.mainloop()
tkinter 函数 after
做两件截然不同的事情 - 如果你像在 """ """ 之间的部分中那样调用它:
master.after(500)
这会让您的 python 程序等待半秒,然后继续。
如果你像 update_canvas
中的循环一样调用它:
master.after(500, update_canvas)
然后 returns 立即,无需等待,但会安排 update_canvas
在未来半秒后发生。
所以你上面的版本是
while counter<10:
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
counter +=1
master.after(500,update_canvas)
没有给出正确的时间延迟,因为循环在没有等待的情况下运行了所有 10 次迭代,并且安排 update_canvas 发生 10 次,全部发生在 now 半秒之后,相隔不到半秒
引号中的版本:
for i in range(1,10):
master.after(500)
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
有一个不同的问题 - 这多次运行循环,每次等待半秒,但 window 甚至还不可见,因为你还没有达到 master.mainloop()
- 所以它为对象设置动画,但您还看不到它。
要解决这个问题,您需要使用未来安排的第一个版本,因此您可以安排它然后调用 mainloop()
,然后让第一个安排下一个。
如果我们这样做:
def update_canvas():
global counter, rec # global lets you change counter and rec from inside the function - avoids 'Unbound local variable'
if counter >= 10:
return # If the counter is big enough, stop and do nothing more
else:
canvas.delete(rec) # Update the rectangle
i = counter
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
counter +=1 # Add to the counter so we don't animate forever
master.after(500,update_canvas) # Schedule the next update for half a second in the future
然后它应该为正方形设置动画。这样循环就消失了,但是我们第一次调用 update_canvas
时,update_canvas
函数本身要求 tkinter 稍后再次调用它。最终计数器变得足够大,它不再要求另一个调用并且动画停止。
您不需要 update_canvas()
中的 while 循环。此外,您不需要重新创建矩形,只需移动它即可:
def update_canvas(counter=0):
if counter < 10:
canvas.move(rec, 10, 10)
master.after(500, update_canvas, counter+1)
我是 python 的新手。目前我的目标是编写一个程序,该程序必须在几秒钟后重复创建和删除对象(矩形、圆形等)。如果我在单独的函数中使用 .after 方法,我会收到错误消息:UnboundLocalError: local variable 'counter' 赋值前引用的时候,看自己的代码。或者,如果我把重复的代码放在程序的主要部分,它只显示最后的状态,而不是中间的状态(见代码中“”和“”之间的描述。我在网上搜索了一段时间但我无法解决。希望你能帮助我。
这是我的代码的简化版本(实际上我正在使用 rec's 列表),它显示了我的问题:
import tkinter as tk
def master_field(text):
""" work field (master) construction"""
master.geometry('500x500+0+0')
master.title(text)
def stop_button():
"""exit"""
b = tk.Button(master, text = 'Exit', width=2, command = master.destroy)
b.place(x = 50, y = 0, width = 100)
def built_canvas():
"""create a canvas"""
canvas=tk.Canvas(master, width = canvas_width, height = canvas_height, borderwidth = 1, bg='light grey', highlightthickness=0, highlightbackground="blue")
canvas.place(x = 0, y = 20)
return canvas
def update_canvas():
while counter<10:
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
counter +=1
master.after(500,update_canvas)
# MAIN
master = tk.Tk()
master_field('MY FIELD')
stop_button()
canvas_width = 200
canvas_height = 200
canvas = built_canvas()
cell_width = 10
x1 = 10
y1 = 10
x2 = x1+10
y2 = y1+10
rec = canvas.create_rectangle(x1,y1,x2,y2, width=0, fill="green")
counter = 0
master.after(500,update_canvas)
"""
# The code below only gives the final state
for i in range(1,10):
master.after(500)
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
"""
master.mainloop()
tkinter 函数 after
做两件截然不同的事情 - 如果你像在 """ """ 之间的部分中那样调用它:
master.after(500)
这会让您的 python 程序等待半秒,然后继续。
如果你像 update_canvas
中的循环一样调用它:
master.after(500, update_canvas)
然后 returns 立即,无需等待,但会安排 update_canvas
在未来半秒后发生。
所以你上面的版本是
while counter<10:
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
counter +=1
master.after(500,update_canvas)
没有给出正确的时间延迟,因为循环在没有等待的情况下运行了所有 10 次迭代,并且安排 update_canvas 发生 10 次,全部发生在 now 半秒之后,相隔不到半秒
引号中的版本:
for i in range(1,10):
master.after(500)
canvas.delete(rec)
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
有一个不同的问题 - 这多次运行循环,每次等待半秒,但 window 甚至还不可见,因为你还没有达到 master.mainloop()
- 所以它为对象设置动画,但您还看不到它。
要解决这个问题,您需要使用未来安排的第一个版本,因此您可以安排它然后调用 mainloop()
,然后让第一个安排下一个。
如果我们这样做:
def update_canvas():
global counter, rec # global lets you change counter and rec from inside the function - avoids 'Unbound local variable'
if counter >= 10:
return # If the counter is big enough, stop and do nothing more
else:
canvas.delete(rec) # Update the rectangle
i = counter
rec = canvas.create_rectangle(x1+i*10,y1+i*10,x2+i*10,y2+i*10, width=0, fill="green")
counter +=1 # Add to the counter so we don't animate forever
master.after(500,update_canvas) # Schedule the next update for half a second in the future
然后它应该为正方形设置动画。这样循环就消失了,但是我们第一次调用 update_canvas
时,update_canvas
函数本身要求 tkinter 稍后再次调用它。最终计数器变得足够大,它不再要求另一个调用并且动画停止。
您不需要 update_canvas()
中的 while 循环。此外,您不需要重新创建矩形,只需移动它即可:
def update_canvas(counter=0):
if counter < 10:
canvas.move(rec, 10, 10)
master.after(500, update_canvas, counter+1)