我有一个循环旋转陀飞轮gif以显示运行过程的函数。该过程完成后,将使用另一个值(开/关)再次调用该函数,并且Label变为✓。如果我只有几个从threadspawner()开始的线程,那么它们就很好了,并将label更改为✓。如果我同时启动许多线程(例如12个),则线程结束得很好,但是一个或两个标签的纺车有时不会更改为✓。

请注意,在下面的示例中,我无法使加载程序停止并更改为✓。也许这是即时通讯混乱的一部分,但是在我的代码中它切换得很好。

我应该以不同的方式表示负载轮还是以不同的方式调用loader('off')?

我尝试为每个线程使用全局变量,并在线程启动时将其设置为True,然后在线程结束时将其设置为true。仅当我在加载器循环中更新变量以获取新值时这才起作用,这意味着我必须为每个线程创建一个不同的加载器函数,这需要大量额外的代码。我尝试使用while循环而不是if,但是它什么也没有改变。

我想为每个线程运行的纺车使用相同的加载器功能。如果那不是最好的方法,请指出正确的方向。

from tkinter import *
import time
import threading
main = Tk()


def threadspawner():
    global var1
    global var2
    print(var1)
    if var1.get() == 2:

        thread1 = threading.Thread(target=lambda: loader(lbl1, 'on')) #<-- starts the spinning wheel to show that something is happening
        thread1.start()
        time.sleep(1)  #start doing stuff here
        loader(lbl1, 'off') #<-- Turns off the spinning wheel
        thread1.join()
    if var2.get() == 2:
        thread2 = threading.Thread(target=lambda: loader(lbl1, 'on')) #<-- starts the spinning wheel to show that something is happening
        thread2.start()
        time.sleep(2)
        loader(lbl2, 'off')#<-- Turns off the spinning wheel
        thread2.join()

var1 = IntVar()
chk1 = Checkbutton(main, text='process1', onvalue=2, offvalue=0, variable=var1)
chk1.grid(row=1)
lbl1 = Label(main, text='')
lbl1.grid(row=1, column=1)

var2 = IntVar()
chk2 = Checkbutton(main, text='process2', variable=var2)
chk2.grid(row=2)
lbl2 = Label(main, text='')
lbl2.grid(row=2, column=1)

strt = Button(main, text='Start', command=lambda: threading.Thread(target=lambda: threadspawner()).start())
strt.grid(columnspan=2)

def loader(label, switch):
    global lbl1
    global lbl2

    #im using images for my program but you do not have them so I use keyboard entries below to represent

    #img = PhotoImage(file='icons\\wheel.gif', format="gif -index 0")
    #img1 = PhotoImage(file='icons\\wheel.gif', format="gif -index 1")
    #img2 = PhotoImage(file='icons\\wheel.gif', format="gif -index 2")
    if switch == 'off':
        label['text'] = '✓'
        return
    if switch == 'on':
        print('starting loop')
        if switch == 'on':
            label['text'] = '/'
        time.sleep(.1)
        if switch == 'on':
            label['text'] = '-'
        time.sleep(.1)
        if switch == 'on':
            label['text'] = '\\'
        time.sleep(.1)
        if switch == 'on':
            loader(label, 'on')
main.mainloop()

最佳答案

您正在执行的操作的问题是switch是局部变量,因此,当启动loader函数时,将启动微调器,但是当其停止时,switch参数将被传递到加载程序功能仍为'on',因此即使将标签设置为'✓',仍将立即重置文本以继续加载动画。当使用参数'off'调用加载程序函数时,switch变量在该函数调用的本地范围内仅具有值'off'

一个快速而肮脏的解决方法是创建一个新的全局变量,该全局变量可用于停止加载器函数永远调用自身。这有很多问题,例如一次只允许使用一个旋转器。

global_switch = 'off'

def loader(label, switch):
    global lbl1, lbl2, global_switch

    if not switch==None:
        global_switch = switch

    if global_switch == 'off':
        ....
    if global_switch == 'on':
        ....
            loader(label, None)
main.mainloop()


但是,我建议使用类更整洁的方法。 (关于将其转换为使用图像而不是文本,有一些未经测试的注释建议)。另外,您不能在主线程之外安全地进行tkinter调用,因此尽管这不是您最初提出的问题,但我已使用rootafter方法代替了线程和time.sleep() s。

这是我建议的解决方案:

from tkinter import *
import time
import threading
main = Tk()


def threadspawner():
    global var1
    global var2
    print(var1.get(),var2.get())
    if var1.get() != 0:
        lbl1.start() #<-- starts the spinning wheel to show that something is happening
        time.sleep(1)  #start doing stuff here
        lbl1.stop() #<-- Turns off the spinning wheel
    if var2.get() != 0:
        lbl2.start() #<-- starts the spinning wheel to show that something is happening
        time.sleep(2)
        lbl2.stop() #<-- Turns off the spinning wheel

class Loader(Label):
    positions_text = '/-\\'
    #positions_imgs = [PhotoImage(file='icons\\wheel.gif', format="gif -index "+str(i)) for i in range(3)]
    def __init__(self, parent, *args, **kwargs):
        kwargs['text']=''
        Label.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.runnng = False
        self.pos = 0
    def start(self):
        self.running = True
        self.parent.after(0,self.update)

    def update(self):
        self.config(text = self.positions_text[self.pos])
        #self.config(image = self.positions_imgs[self.pos])
        self.pos = (self.pos+1)%len(self.positions_text)
        #self.pos = (self.pos+1)%len(self.positions_imgs)
        if self.running:
            self.parent.after(100,self.update)
        else:
            self.config(text = '✓')
    def stop(self):
        self.running = False



var1 = IntVar()
chk1 = Checkbutton(main, text='process1', onvalue=2, offvalue=0, variable=var1)
chk1.grid(row=1)
lbl1 = Loader(main) # create an instance of the Loader class
lbl1.grid(row=1, column=1)

var2 = IntVar()
chk2 = Checkbutton(main, text='process2', variable=var2)
chk2.grid(row=2)
lbl2 = Loader(main) # create an instance of the Loader class
lbl2.grid(row=2, column=1)

strt = Button(main, text='Start', command=lambda: threading.Thread(target=threadspawner).start())
strt.grid(columnspan=2)

main.mainloop()


注意:我还对代码进行了其他一些小的更改。

关于python - 手纺车功能并不总是退出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42168277/

10-10 15:18