2013-08-28 54 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'的嵌套调用可能会耗尽列表,但在当前通过队列完成之前立即添加一个新列表。 –