2013-07-24 37 views
2

我一直有困難與多線程和tkinter。 slxl是一個模塊,我使用的作品,其職能不返回值(只是爲了確保不存在混淆。)函數的線程和隊列

這裏是代碼具有在過去的工作:

#relevant tkinter code 
    def create_widgets(): 

     self.updatebttn = Button(self, text='Auto Update', command=self.spawnthread) 
     self.updatebttn.grid(row=1, column=0, sticky=N) 

     self.progressbar = Progressbar(self, orient='horizontal', 
             length=300, mode='determinate') 
     self.progressbar.grid(row=1, column=1, sticky=W) 
     self.progressbar["maximum"] = (slxl.sizeFinder()) * 1.1 


    def spawnthread(self): 
     self.updatebttn.config(state="disabled") 
     self.thread = ThreadedClient1(self.queue) 
     self.thread.start() 
     self.periodiccall() 

    def periodiccall(self): 
     if self.thread.is_alive(): 
      self.after(100, self.periodiccall) 
      self.progressbar.step(500) 
     else: 
      self.updatebttn.config(state="active") 
      self.progressbar.stop() 

class ThreadedClient1(threading.Thread): 
    def __init__(self, queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 
    def run(self): 
     time.sleep(1) 
     importer = slxl.runImportAndCoordAdder() 
     self.queue.put(importer) 

的事情是,我希望ThreadedClient1能夠把它放入隊列的函數,在這種情況下,作爲參數slxl.runImportAndCoordAdder(),因爲我不止一次地使用ThreadedClient不同的功能(我有一個相同的使用它後來在程序只有一個不同的功能),我不喜歡有ThreadedClient1ThreadedClient2,唯一的區別是importer =不同的功能。

我也試圖與拉姆達的解決方案爲這樣:

def spawnthread(self): 
    self.updatebttn.config(state="disabled") 
    self.thread = ThreadedClient1(self.queue, lambda: slxl.runImportAndCoordAdder()) 
    self.thread.start() 
    self.periodiccall() 

#periodic call is the same 

class ThreadedClient1(threading.Thread): 
    def __init__(self, queue, fcn): 
     threading.Thread.__init__(self) 
     self.queue = queue 
     self.fcn = fcn 
    def run(self): 
     time.sleep(1) 
     self.queue.put(lambda: self.fcn) 

這沒有工作,因爲它忽略了我感興趣的功能,不爲所動的進度有點/禁用和啓用按鈕,然後結束。

我在做什麼錯?

編輯: 問題解決了。儘管如此,另一位發生了。我想將spawnthreadperiodiccallThreadedClient轉移到我具有的窗口小部件模板模塊,並將其一般化,以便我可以輕鬆使用它們。我這樣做:

def spawnthread(self, widget): 
    widget.config(state="disabled") 
    self.thread = ThreadedClient1(self.queue) 
    self.thread.start() 
    self.periodiccall() 

哪些工作,直到我試圖推廣periodiccall以及。

#... 
     self.periodiccall(widget=widget) 

    def periodiccall(self, widget=None): 
     if self.thread.is_alive(): 
      self.after(100, self.periodiccall) 
      self.progressbar.step(500) 
      #print widget 
     else: 
      widget.config(state="active") 
      self.progressbar.stop() 

我彈出print widget看看發生了什麼,因爲我不斷收到屬性錯誤。看來發生的事情是,它第一次運行它知道什麼「小部件」的功能,然後它變成None我希望它通過after聲明中調用self.periodiccall。至少,這是我認爲正在發生的事情。如何在這個遞歸函數中刪除這個錯誤並使widget成爲一個變量?

回答

1

的問題是,當您使用它作爲一個參數爲ThreadedClient1不調用該函數:

class ThreadedClient1(threading.Thread): 
    # ... 
    def run(self): 
     time.sleep(1) 
     self.queue.put(lambda: self.fcn) 

這僅僅是返回到你作爲參數傳遞的拉姆達的引用的函數,而不是致電slxl.runImportAndCoordAdder()的結果。它應該是:

class ThreadedClient1(threading.Thread): 
    # ... 
    def run(self): 
     time.sleep(1) 
     self.queue.put(self.fcn()) 

或直接用參考另一種解決方案(不lambda表達式):

def spawnthread(self): 
    self.updatebttn.config(state="disabled") 
    self.thread = ThreadedClient1(self.queue, slxl.runImportAndCoordAdder) 
    self.thread.start() 
    self.periodiccall() 

class ThreadedClient1(threading.Thread): 
    # ... 
    def run(self): 
     time.sleep(1) 
     self.queue.put(self.fcn()) 
+0

完美。這正是我需要的。我正在使用lambdas,因爲我希望能夠將spawnthread,periodicall和threadedclient轉儲到我的窗口小部件模板模塊中以實現代碼的清潔。 –

+0

我有一個後續問題;我將它添加到原始問題中。 –