tkinter:如何在同一处理程序中的小部件更改之间插入延迟?

问题描述

大约两年前,当我试图在Tkinter画布上模拟LED时,我问了类似的问题。然后,解决方案是使用canvas after()方法而不是sleep()函数在小部件更新之间引入延迟。

从那时起,我发现了tk_tools模块,该模块具有用于创建LED的内置功能,太好了!但是,我现在遇到了与以前相同的问题,那就是:如何在每个LED的打开(变为绿色)之间有1秒的延迟?

运行下面的代码时,实际上发生的情况是LED显示为熄灭状态(灰色),然后当我单击“开始”按钮时,有4秒的延迟,之后所有LED同时打开。 / p>

谢谢。 约翰尼

# LED array simulation

from tkinter import *
import tk_tools as tkt
from time import *

# turn on LEDs (change to green) with a 1-second delay between each
def turn_on():
    for led in range(4):
        led_array[led].to_green()
        sleep(1)

# list to hold a 4-LED array
led_array = []

# GUI
root = Tk()

# create 4 LED widgets,store them in led_array[],display them
for i in range(4):
    led_array.append(tkt.Led(root,size=30))
    led_array[i].grid(row=0,column=i)

# create button to initiate LED turn-on sequence
start = Button(root,text='Start',padx=20,command=turn_on)
start.grid(row=1,columnspan=4)



root.mainloop()

解决方法

我猜每当回调函数完成执行时,所有的LED都会一次发光。因此,我决定创建一个线程并使用after()来停止时间(sleep()停止主线程,这使其耗时4秒钟)

# LED array simulation

from tkinter import *
import tk_tools as tkt
from time import *
import threading
import sys

class Testing(Tk):
    def __init__(self):
        super().__init__()
        self.led_array = []
        for i in range(4):
            self.led_array.append(tkt.Led(self,size=30))
            self.led_array[i].grid(row=0,column=i+1)
        self.start = Button(self,text='Start',padx=20,command=self.zawardu)
        self.start.grid(row=1,columnspan=4)
    def zawardu(self):
        a=threading.Thread(target=self.turn_on)
        a.start()
    def turn_on(self):
        self.start.config(state=DISABLED) # to stop creating another thread unnec..
        for led in range(len(self.led_array)):
            self.led_array[led].to_green()
            self.after(1000) # stops time
        self.start.config(state=NORMAL) 
        sys.exit(0) # ensures after exec. thread is killed
# class format to use after() and threading to reset the button status
Testing().mainloop()
,

最好避免睡眠,这会停止应用程序并使用after。可以将调用链接到after回调,以便每个调用下一​​个,或者为每个led循环调用,但延迟分别为1、2、3和4秒。

链接版本:

# LED array simulation

from tkinter import *
import tk_tools as tkt

# list to hold a 4-LED array
led_array = []

# GUI
root = Tk()

# create 4 LED widgets,store them in led_array[],display them
for i in range(4):
    led_array.append(tkt.Led(root,size=30))
    led_array[i].grid(row=0,column=i)

# Both answers are common to here.

def on_after( led_list ):
    led_list[0].to_green() # Set first item in the list.
    if len( led_list ) > 1:
        # Call on_after again with a shortened list.
        root.after( 1000,on_after,led_list[1:] )
    else:
        # Enable the start button
        start.config( state = NORMAL )

# turn on LEDs (change to green) with a 1-second delay between each
def turn_on():
    start.config( state = DISABLED ) # Disable the button
    root.after( 1000,led_array)

# create button to initiate LED turn-on sequence
start = Button(root,command=turn_on)
start.grid(row=1,columnspan=4)

root.mainloop()

循环版本:

# Both answers are common to here.
def on_after( led ):
    led.to_green()

def enable():
    start.config( state = NORMAL )

# turn on LEDs (change to green) with a 1-second delay between each
def turn_on():
    start.config( state = DISABLED ) # Disable the button
    for ix,led in enumerate( led_array ):
        # Call on_after 4 times with 1 to 4 second delays
        root.after( 1000 * (1+ix),led )
    root.after( 1000*(ix+1),enable )

# create button to initiate LED turn-on sequence
start = Button(root,columnspan=4)

root.mainloop()

尽管在这种情况下,循环版本可能更容易理解,但我可能会使用链式版本。