简体   繁体   English

当我调用update_idletasks()时,Tkinter有时会冻结

[英]Tkinter is sometimes freezing when I call update_idletasks()

I'm putting together a tkinter gui app and occasionally when loading a new frame and adding it to a notebook the gui will freeze up on the call to update. 我正在组装一个tkinter gui应用程序,偶尔在加载新框架并将其添加到笔记本中时,gui会冻结呼叫以进行更新。 I'm not sure what to provide for code, I have a lot of subclassing going on so posting all of that would get ridiculous, and I'm not sure if it would be usefull at all. 我不确定为代码提供什么,我正在进行很多子类化,因此发布所有这些将变得荒谬,而且我不确定它是否会有用。

def _handle_events_button(self):
    ntbk = self.find_notebook()
    print("1: " + str(int(time.time())))
    w = EventListDetailsCombo(ntbk)
    print("2: " + str(int(time.time())))
    w.load()
    print("3: " + str(int(time.time())))
    w.add_to_notebook(ntbk)
    print("4: " + str(int(time.time())))
    # clipboard.root.update_idletasks()
    print("5: " + str(int(time.time())))
    ntbk.select(w)
    print("6: " + str(int(time.time())))

The output of the prints is this: 印刷品的输出是这样的:

# Working correctly 
1: 1555952235
2: 1555952235
3: 1555952235
4: 1555952235
5: 1555952237
6: 1555952237

# Hang / Delay
1: 1555952240
2: 1555952240
3: 1555952240
4: 1555952240
5: 1555952266
6: 1555952266

That is with update_idletasks() without update_idletasks() all of these outputs are within 1-2 seconds of each other. 也就是说,使用update_idletasks()而不使用update_idletasks()时,所有这些输出都在1-2秒内。 The hang instead happens in the mainloop update_idletasks 挂起发生在mainloop update_idletasks中

Some Notes: 一些注意事项:

  • It doesn't freeze consistently it seems pretty random, but it does seem to happen every 4 to 5 tries. 它并不会持续冻结,这似乎是随机的,但似乎每4到5次尝试就会发生一次。
  • The length of the freeze also seems random sometimes its 30 seconds sometimes its several minutes. 冻结的时间长度似乎也是随机的,有时是30秒,有时是几分钟。
  • If I click other buttons while its frozen it will execute those actions after the freeze stops 如果在冻结期间单击其他按钮,它将在冻结停止后执行这些操作
  • usually if I terminate the app from pycharm the frame will load for a second before the app terminates. 通常,如果我从pycharm终止应用程序,则框架会在应用程序终止之前加载一秒钟。

I'm not sure where to go from here, any pointers on things I could look into? 我不确定从这里走到哪里,关于我可以研究的事情有什么指针吗?

Edit: So I went through and removed any calls to update and now it just hangs after this code, I assume in the main loop update step but I'm not really sure how to check that assumption, this _handle_events_button function is called directly from the events button so there shouldn't be anymore of my code after this point. 编辑:因此,我经历并删除了所有对update的调用,现在它只是在此代码后挂起,我假设在主循环更新步骤中,但是我不确定如何检查这一假设,因此直接从_handle_events_button函数中调用事件按钮,因此此刻之后不再应该包含我的代码。

Edit 2: If I leave update_idletasks in and run a profiler on it, when its working properly it looks like this: 编辑2:如果我将update_idletasks留在其中并在其上运行分析器,则当其正常工作时,它看起来像这样:

在此处输入图片说明

Everything looks the same on the runs where it hangs, except that instead of method 'call' taking about 1000ms it takes 25000ms or more, with roughly the same number of calls to 'call'. 在挂起的运行中,所有内容看起来都是相同的,除了使用方法“ call”花费大约1000ms而不是花费25000ms或更长时间,而调用“ call”的次数大致相同。

Edit 3: I have added in the output of the print statements. 编辑3:我已经在打印语句的输出中添加了。 Also I can not throw any of this function into a separate thread since it is all just preparing widgets. 另外,我不能将任何此函数放入单独的线程中,因为它们都只是在准备小部件。

You don't want to call update / update_idletasks if you have a persistent event loop running. 不想打电话给update / update_idletasks如果你有一个持续的事件循环运行。 These functions are the alternative to a persistent event loop. 这些函数是持久事件循环的替代方法

When you call it from an event handler, you are essentially running a temporary nested event loop. 从事件处理程序调用它时,实际上是在运行一个临时的嵌套事件循环。 Which blocks the code until all applicable pending events are processed -- and can also have other undesirable side effects since the actions your current event handler is supposed to perform are only half complete and other code may see the application in an inconsistent state. 它会阻塞代码,直到处理完所有适用的待处理事件为止,并且还会产生其他不良影响,因为当前事件处理程序应该执行的动作仅完成了一半,其他代码可能会看到应用程序处于不一致状态。

So after a lot of banging my head on the desk I think I figured this out. 因此,在将我的头撞到桌子上很多次之后,我想我明白了。 To start with it seems like tkinter is just slow to load widgets, not sure if this is because of how many widgets I have (not all that many, probably less than 100, maybe less than 50 in each frame I load) or due to all the subclassing I'm doing (probably more than I should). 首先,似乎tkinter加载小部件的速度很慢,不确定这是否是因为我有多少个小部件(加载的每一帧不是全部,可能少于100个,也许少于50个)或由于我正在做的所有子类化(可能比我应该做的还要多)。 Its annoying but workable for now. 它令人烦恼,但目前仍可行。

What seemed to fix the occasional freeze was to stop using the tkcalender datepicker widget. 解决临时冻结问题的方法是停止使用tkcalender datepicker小部件。 As soon as I switched that out for an entry and frame based custom widget, things stopped freezing, now every time I load a frame it takes pretty much the same amount of time, still kinda slow, but consistent, which is all I really need for now. 一旦我将其切换为基于条目和基于框架的自定义小部件,事情就停止了冻结,现在每次加载框架所需的时间几乎相同,虽然仍然很慢,但始终如一,这是我真正需要的目前。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM