Tkinter long-running window freezes

MRAB python at mrabarnett.plus.com
Fri Feb 26 20:06:06 EST 2021


On 2021-02-26 23:59, John O'Hagan wrote:
> On Fri, 26 Feb 2021 08:19:14 +0100
> Christian Gollwitzer <auriocus at gmx.de> wrote:
> 
>> Am 26.02.21 um 06:15 schrieb John O'Hagan:
> [...]
>> > 
>> > I've followed your suggestions as per my last post, and can confirm
>> > the same freezing behaviour when running your code directly as a
>> > tclsh script on Debian Testing, Tcl 8.6.11.  
>> 
>> You might report this as a bug to the Tcl bugtracker 
>> https://core.tcl-lang.org/tk/ticket
>> 
>> I guess the problem is with the steady creation of widgets. Tk was
>> not meant to be used like that. Tkinter creates new widget names for
>> each widget with random numbers, just like the Tcl code above does,
>> whereas in a usual Tcl/Tk program the names are given by the
>> programmer.
> 
> Thanks, I will make the bug report. However, based  on your comments
> above, it looks similar to this one, closed as invalid 16 years ago:
> 
> https://core.tcl-lang.org/tk/tktview/1173484fffffffffffff
> 
> This was also related to memory "creep" caused by Tk's cache of names,
> which AIUI is a Tk design feature (but I don't know Tk!).
> 
>> Can you also check this program, which reuses the same widget path
>> name, albeit does the creation/destruction in cycles:
>> 
>> ======================
>> package require Tk
>> 
>> proc randint {} {
>>      expr {int(rand()*10000000)}
>> }
>> 
>> proc display {label} {
>>      destroy $label
>>      set label [label .l -text [randint]]
>>      pack $label
>>      after 100 [list display $label]
>> }
>> 
>> display [label .l]
>> ========================
>> 
> 
> I have tried this overnight and it is still running, not frozen and with
> no apparent increase in memory use. I guess that is likely the issue. I
> don't know Tcl/Tk - is there a way to emulate the above approach of
> re-using the widget name in tkinter?
> 
>> As mentioned by others, typically you wouldn't continuously recreate
>> new widgets, but either update the text of the widget
>> (label['text']="New text") or attaching a StringVar() )
>> 
>> or, if you must rearrange the widgets, you pack_forget() them and
>> then repack them.
>> 
>> 	Christian
> 
> This is possible of course, but will require more than a repack. In my
> use case, each widget is an attribute of a Python object, intended
> control and display data about that object, and there is an
> indeterminate number of such objects at any given time. I had
> assumed I could just destroy the widget and let the object go out of
> scope to be garbage collected. I'll need to redesign this altogether if
> I can't rely on Tk to manage memory.
> 
> IMHO it's quite surprising if .destroy doesn't free all the resources
> used by a widget!
> 
I've look in Lib\tkinter\__init__.py and it appears that you can give it 
a name, so:

from tkinter import *
from random import randint

root = Tk()

def display(label):
      label.destroy()
      label = Label(name='my_label', text=randint(0, 9))
      label.pack()
      root.after(1, display, label)

display(Label(name='my_label'))
mainloop()

When I do that I'm not seeing a memory rise.


More information about the Python-list mailing list