2013-08-28 91 views
3

我是Tkinter的新手,所以我很抱歉,如果這很容易,但我已經搜索了幾個小時,並且無法弄清楚。我想要做的是在主循環閒置後,我總是想調用checkForGroupUpdates()函數。當我運行下面的代碼時,它只運行一次。每當主循環閒置時我都無法弄清楚它的運行情況。我很感激幫助。Tkinter只會打電話給after_idle一次

from Tkinter import * 
import random 

class Network(Frame): 
    """ Implements a stop watch frame widget. """                
    def __init__(self, parent=None, **kw):  
     Frame.__init__(self, parent, kw) 
     self.makeWidgets()  

    def makeWidgets(self):      
     """ Make the time label. """ 
     self._canvas = Canvas(self, width=600, height=400) 
     self._canvas.pack() 

    def checkForGroupUpdates(self): 
     print "checking" 
     h=0 
     this=10 
     while this>.0001: 
      this=random.random() 
      print h 
      h=h+1 
     print "checked" 


def main(): 
    root = Tk() 
    nw = Network(root) 
    nw.pack(side=TOP) 

    root.after_idle(nw.checkForGroupUpdates) 
    root.mainloop() 


if __name__ == '__main__': 
    main() 
+0

你是什麼意思「每次主循環空閒」?大部分時間空閒,除了點擊按鈕時。 –

+0

是的,理想情況下,我希望上述程序基本上可以持續運行checkForGroupUpdates(),因爲大部分時間主應用程序應該處於空閒狀態。我希望checkForGroupUpdates()在每次主循環閒置時運行。 – user1763510

+0

那麼,當程序沒有做別的事情時,你希望它每秒運行數千次?它是否真的需要經常運行,還是每秒只能運行幾次?讓它在應用程序閒置時連續運行很少比僅僅每秒調用幾次更有用。 –

回答

7

而不是在應用程序閒置時一直調用該函數,您應該每隔一秒鐘調用它一次。例如,如果您要檢查10次每一秒,你會做這樣的事情:

def checkForGroupUpdates(self): 
    <do whatever you want> 
    self.after(100, self.checkForGroupUpdates) 

一旦你調用該函數一次,它會安排自己要在100毫秒再次調用。這將繼續下去,直到程序退出。如果程序變爲「非空閒」(即:響應按鈕單擊),此功能將暫停,因爲tkinter是單線程的。一旦程序再次空閒,檢查將繼續。

4

@ user1763510,請注意,在Bryan Oakley的回答中,他有checkForGroupUpdates再次致電self.after。這是因爲self.after只會調用單個,所以重複調用需要在第一次調用函數時調用它自己。這樣,它不斷地自行調用。

after_idle()功能也是如此。您必須再次在底部撥打checkForGroupUpdates再撥after_idle()

以下是關於afterafter_idle等的文檔。在after說明中甚至有一個小例子,這說明了這一點。

文檔:http://effbot.org/tkinterbook/widget.htm

從上述鏈路實施例,下after描述:

#Method 1 
class App: 
    def __init__(self, master): 
     self.master = master 
     self.poll() # start polling 

    def poll(self): 
     ... do something ... 
     self.master.after(100, self.poll) 

要使用after_idle相反,它看起來像這樣:

#Method 2 
class App: 
    def __init__(self, master): 
     self.master = master 
     self.poll() # start polling 

    def poll(self): 
     ... do something ... 
     self.master.update_idletasks() 
     self.master.after_idle(self.poll) 

通知加入self.master.update_idletasks()一行。這將繪製GUI並處理按鈕按下和事物。否則,after_idle()將吸收所有資源,並且不會讓mainloop()中的GUI自行更新。

替代使用

 self.master.update_idletasks() 
     self.master.after_idle(self.poll) 

是使用:

 #Method 3 
     self.master.update_idletasks() 
     self.master.after(0, self.poll) 

使用self.master.after(0, self.poll)是我的首選技術,因爲它可以讓我輕鬆地將0改爲別的東西,如果我決定我不要不需要不斷運行self.poll。通過將延遲時間增加至少1 ms,您不再需要撥打self.master.update_idletasks()。所以,這個工程太:

 #Method 4 
     self.master.after(1, self.poll) 

還要注意,上面所有的例子,在__init__函數調用self.poll()就是踢它全部關閉,並存儲masterself.master需要簡單地讓裏面poll你可以調用例如,afterafter_idle功能通過self.master.after_idle

問:這是穩定的嗎?它有效嗎?
答:我使用上面的方法3運行了一個測試代碼,時間約爲21小時,並且它整個運行時間穩定,允許GUI可用和全部。

問:以上每種方法的速度比較是什麼?
答:

  • 方法1:(我沒有加速測試)
  • 方法2:〜0.44毫秒/迭代
  • 方法3:〜0.44毫秒/迭代
  • 方法4 :〜1.61 ms /迭代

問:哪個是我的首選方法?
答:方法3或4.

+0

從'after_idle'調用的函數調用'after_idle'有點危險。可能發生的情況是,你永遠不會給tkinter一個完全耗盡空閒隊列的機會,這意味着它永遠沒有機會服務任何其他可能正在等待的事件。 –

+0

是不是'update_idletasks()'解決了什麼問題?我已經運行了一個快速測試,看起來像我上面介紹的那樣工作。對於'......做些事情......'我正在打印「測試」,並且在後臺打印時,我製作的GUI會顯示。 –

+0

你必須記住,這個函數是由服務於空閒隊列的tkinter進程調用的。所以,設想一個函數關閉一個項目(即:這個函數),執行它,然後檢查隊列中是否還有其他東西。如果有,它會處理它。所以,在這之前,請檢查您是否在隊列中添加了新內容。它永遠不會用完隊列中的項目,因爲每個項目都被取消,另一個被添加。對'update_idletasks'的嵌套調用可能會耗盡列表,但在當前通過隊列完成之前立即添加一個新列表。 –