tkinter 不会刷新小部件
tkinter wont refresh widget
我想写一个只有一个按钮的程序,按下那个按钮后,程序会开始制作 3 个标签,然后每 1 秒改变一次每个标签的颜色。
看起来很简单,我写了下面的代码:
import tkinter as tk
from time import sleep
def function():
mylist=list()
for i in range(3):
new_label=tk.Label(window,text='* * *',bg='yellow')
new_label.pack()
mylist.append(new_label)
print('First state finished')
sleep(1)
for label in mylist:
label.config(bg='red')
print('one label changed')
sleep(1)
window = tk.Tk()
window.geometry('300x300')
btn=tk.Button(window,text='start',command=function)
btn.pack()
tk.mainloop()
首先,应用程序看起来像这样(没问题):
其次它看起来像这样(它不正常,因为它在终端上打印但没有更新标签):
第三个看起来像这样(最后应用程序必须像这样并且没问题):
但我需要立即查看变化并因此使用睡眠。
谢谢大家。
我建议使用 tkinter 的 .after(delay, callback) 方法来设置颜色。
希望这就是你想要的。
import tkinter as tk
def start():
global mylist
mylist = list()
for i in range(3):
new_label = tk.Label(window, text='* * *', bg='yellow')
new_label.pack()
mylist.append(new_label)
delay = 1000 # delay in seconds
for label in mylist:
# Additional delay so that next color change
# is scheduled after previous label color change
delay += 1000
schedule_color_change(delay, label)
def schedule_color_change(delay, label):
print("schedule color change for:", label)
label.after(delay, set_color, label)
def set_color(label):
print("setting color of:", label)
label.config(bg="red")
window = tk.Tk()
window.geometry('300x300')
btn = tk.Button(window, text='start', command=start)
btn.pack()
tk.mainloop()
问题
问题出在你的sleep(1)
,因为它是一个暂停当前线程执行一定秒数的函数,所以就像整个脚本都停止了
解决方案
解决方法是用一个目标函数实例化Thread,调用start(),让它开始工作。所以你必须使用包含在线程中的 timer
,然后是线程模块中的计时器 (import threading
)
在第一个“for”循环中,删除你的 sleep(1) 并写入例如 Time_Start_Here = threading.Timer (2, function_2)
然后当然是 Time_Start_Here.start()
开始。
start_time=threading.Timer(1,function_2)
start_time.start()
相反,您必须删除第二个“for”循环并将其中的内容写入……在将被调用的新函数中。接下来你需要创建函数
def function_2():
for label in mylist:
label.config(bg='red')
label.pack()
print('one label changed')
在Meritor的指导下,我按照after
的方法,不眠不休的写了下面的递归代码:
import tkinter as tk
def recursive(i, listt):
lbl = listt[i]
if i >= 0:
lbl.config(bg='orange')
i -= 1
lbl.after(500, recursive, i, listt)
def function():
mylist = list()
for i in range(3):
new_label = tk.Label(window, text='* * *', bg='yellow')
new_label.pack()
mylist.append(new_label)
print('all label created')
# 2 is length of list minus 1
recursive(2, mylist)
window = tk.Tk()
window.geometry('300x300')
tk.Button(window, text='start', command=function).pack()
tk.mainloop()
很可能我的代码没有优化,因为它使用递归,如果你知道更好的,请告诉我
我想写一个只有一个按钮的程序,按下那个按钮后,程序会开始制作 3 个标签,然后每 1 秒改变一次每个标签的颜色。
看起来很简单,我写了下面的代码:
import tkinter as tk
from time import sleep
def function():
mylist=list()
for i in range(3):
new_label=tk.Label(window,text='* * *',bg='yellow')
new_label.pack()
mylist.append(new_label)
print('First state finished')
sleep(1)
for label in mylist:
label.config(bg='red')
print('one label changed')
sleep(1)
window = tk.Tk()
window.geometry('300x300')
btn=tk.Button(window,text='start',command=function)
btn.pack()
tk.mainloop()
首先,应用程序看起来像这样(没问题):
其次它看起来像这样(它不正常,因为它在终端上打印但没有更新标签):
第三个看起来像这样(最后应用程序必须像这样并且没问题):
但我需要立即查看变化并因此使用睡眠。 谢谢大家。
我建议使用 tkinter 的 .after(delay, callback) 方法来设置颜色。
希望这就是你想要的。
import tkinter as tk
def start():
global mylist
mylist = list()
for i in range(3):
new_label = tk.Label(window, text='* * *', bg='yellow')
new_label.pack()
mylist.append(new_label)
delay = 1000 # delay in seconds
for label in mylist:
# Additional delay so that next color change
# is scheduled after previous label color change
delay += 1000
schedule_color_change(delay, label)
def schedule_color_change(delay, label):
print("schedule color change for:", label)
label.after(delay, set_color, label)
def set_color(label):
print("setting color of:", label)
label.config(bg="red")
window = tk.Tk()
window.geometry('300x300')
btn = tk.Button(window, text='start', command=start)
btn.pack()
tk.mainloop()
问题
问题出在你的sleep(1)
,因为它是一个暂停当前线程执行一定秒数的函数,所以就像整个脚本都停止了
解决方案
解决方法是用一个目标函数实例化Thread,调用start(),让它开始工作。所以你必须使用包含在线程中的 timer
,然后是线程模块中的计时器 (import threading
)
在第一个“for”循环中,删除你的 sleep(1) 并写入例如 Time_Start_Here = threading.Timer (2, function_2)
然后当然是 Time_Start_Here.start()
开始。
start_time=threading.Timer(1,function_2)
start_time.start()
相反,您必须删除第二个“for”循环并将其中的内容写入……在将被调用的新函数中。接下来你需要创建函数
def function_2():
for label in mylist:
label.config(bg='red')
label.pack()
print('one label changed')
在Meritor的指导下,我按照after
的方法,不眠不休的写了下面的递归代码:
import tkinter as tk
def recursive(i, listt):
lbl = listt[i]
if i >= 0:
lbl.config(bg='orange')
i -= 1
lbl.after(500, recursive, i, listt)
def function():
mylist = list()
for i in range(3):
new_label = tk.Label(window, text='* * *', bg='yellow')
new_label.pack()
mylist.append(new_label)
print('all label created')
# 2 is length of list minus 1
recursive(2, mylist)
window = tk.Tk()
window.geometry('300x300')
tk.Button(window, text='start', command=function).pack()
tk.mainloop()
很可能我的代码没有优化,因为它使用递归,如果你知道更好的,请告诉我