我有一个循环旋转陀飞轮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调用,因此尽管这不是您最初提出的问题,但我已使用
root
的after
方法代替了线程和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/