Tkinter调用root.after时忽略延迟、后续代码提前执行如何解决?
问题根源
root.after() 是Tkinter的非阻塞异步调度接口,它仅会将你传入的任务注册到Tkinter事件队列,到指定延迟后自动执行,注册完成后会立刻向下运行当前函数的后续代码,不会等待所有注册的延时任务执行完毕。你看到的倒计时正常播放,是因为这些倒计时更新任务已经被成功注册到事件队列按时执行,但后续的spam逻辑没有和倒计时的结束时机绑定,所以会提前运行。
修复方案
将倒计时结束后需要执行的逻辑封装为独立函数,在最后一次倒计时的延时任务中触发该函数即可,不要直接把后续逻辑写在after注册代码的后面。
修改后的代码参考:
def run_spam_logic(): # 把原来写在after注册代码后面的逻辑都移到这个函数里 x = 100 y = 100 try: with open(PreferencesStorage['FilePath'], 'r') as SpamText: while PreferencesStorage['loop']: for word in SpamText: # fail safe 1 if x < 21 and y < 21: break TempX, TempY = mouse.position x = int(TempX) y = int(TempY) # fail-safe 2 if keyboard.is_pressed('ctrl+d'): break keyboard.write(word) print(word) # return to begining when at end, thats why its outside of the loop SpamText.seek(0) for word in SpamText: keyboard.write(word) except FileNotFoundError: NoFile = tk.Label(frame, text = 'Please Select A File', padx=10, pady=5, fg=Modes[mode.get()][2]['text'], bg=Modes[mode.get()][3]['background']) NoFile.pack() def StartTheSpam(): global TimeLable, ErrorLabel, mouse # destoryes error labels and the countdown timer try: for child in root.winfo_children(): if child == TimeLable or child == ErrorLabel: child.destroy() except NameError: pass # needed for fail-safe 1 mouse = MouseController() countdown_value = 5 counter = tk.StringVar() counter.set(countdown_value) TimeLable = tk.Label(frame, textvariable=counter, padx=10, pady=5, bg=Modes[mode.get()][3]['background'], fg=Modes[mode.get()][2]['text']) TimeLable.pack() # 注册倒计时更新任务 for countdown in range(1, countdown_value): root.after(1000 * countdown, counter.set, countdown_value - countdown) # 注册倒计时结束后的执行任务,延迟5秒和倒计时结束时机对齐 root.after(1000 * countdown_value, run_spam_logic)
注意事项
不要尝试用time.sleep()来做等待,该方法会阻塞Tkinter的事件循环,直接导致倒计时界面卡死无法更新。
内容的提问来源于stack exchange,提问作者richmail
相关产品推荐
相关产品推荐

