2017-02-10 44 views
2

我有一個功能,可以循環顯示正在運行的過程。當過程完成時,函數再次以不同的值被調用(開/關),並且Label變爲✓。如果我只有threadspawner()的幾條線索開球,那麼他們完成罰款並將label更改爲✓。如果我在同一時間開始很多線程(如12),那麼線程完成得很好,但一個或兩個標籤的旋轉輪有時不會變爲✓。轉輪功能並不總是退出

請注意,在下面的示例中,我無法讓加載程序停止並更改爲✓。也許這是即時通訊的一部分,但在我的代碼中,它切換得很好。

我應該不同地表示加載輪還是以不同的方式調用加載程序('off')?

我試着對每個線程使用全局變量,並在線程啓動時將其設置爲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() 
+0

這裏似乎沒有任何東西可以保證你打開*之後關閉微調器*。 – user2357112

+0

當線程啓動時變量'on'以及變量'off'結束然後更新加載程序循環中的變量是唯一可靠的方法嗎? – sidnical

+0

你爲什麼從單獨的線程關閉它?在你等待另一個線程完成之前,你爲什麼要關閉微調器? – user2357112

回答

1

與你在做什麼的問題是,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() 

注:我也取得了在代碼中的一些其他小的改動。