2

I want to query a widget's size after changing its contents. Here's a demonstration:

import tkinter as tk

win = tk.Tk()

label = tk.Label(win)
label.pack()

def callback1():
    label['text'] = 'hello world'
    win.after_idle(callback2)

def callback2():
    print('label width:', label.winfo_width())

win.after(0, callback1)    
win.mainloop()

According to the documentation, callbacks queued with after_idle should only be executed when there's nothing else to do:

Registers a callback that is called when the system is idle. The callback will be called there are no more events to process in the mainloop.

And yet, callback2 is clearly executed before the label is resized, because the output of the program is this:

label width: 1

Even adding a call to update_idletasks() doesn't change this output. Only if win.update_idletasks() is called in both callback1 and callback2, the correct size is printed. I really don't understand why it's necessary to call it twice.

Question

Why is callback2 being executed before the label is resized? How can I ensure that label.winfo_width() returns the correct size?

Limitations

The main goal of this question is to understand how/when tkinter executes (idle) tasks. I want to find out how to correctly queue tasks so that they're executed only after the GUI has updated itself. I'm not really interested in workarounds such as these:

  • I'd prefer to avoid using update() because I don't understand how it causes race conditions or when it's safe to use. (In my real code, all of this would be executed inside an event handler, which the documentation explicitly states should be avoided.)
  • I also want to avoid using the <Configure> event. This is because there might be an arbitrary number of widgets changing size, and I cannot reasonably be expected to bind event handlers to all of their <Configure> events. I really just need a way to execute a callback function after all the resizing has taken place.
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
  • 1
    I don't have the explanation you are asking for, but if you call update on the label `label.update()`, right after setting its text, the geometry is adjusted at once. – Reblochon Masque May 08 '20 at 14:39

0 Answers0