简体   繁体   中英

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. 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. The hang instead happens in the 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.
  • The length of the freeze also seems random sometimes its 30 seconds sometimes its several minutes.
  • 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.

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.

Edit 2: If I leave update_idletasks in and run a profiler on it, when its working properly it looks like this:

在此处输入图片说明

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'.

Edit 3: I have added in the output of the print statements. 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. 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). Its annoying but workable for now.

What seemed to fix the occasional freeze was to stop using the tkcalender datepicker widget. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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