Based on this answer, I successfully created my own widget where labels are wrapped automatically in a Text element using window_create.
I’m also able to destroy these labels using nametowidget. However, the window element of the deleted widgets remains and is returned by dump.
Here is my minimal reproducible example:
import tkinter as tk
root = tk.Tk()
btn_frame1 = tk.Frame(root)
btn_frame1.pack(side='top', fill='x')
create_labels_btn = tk.Button(btn_frame1, text='Create Labels')
create_labels_btn.pack(side='left')
delete_labels_btn = tk.Button(btn_frame1, text='Delete Labels')
delete_labels_btn.pack(side='right')
label_text_field = tk.Text(root, height=7, width=40)
label_text_field.pack(side='top')
dump_text_field_btn = tk.Button(root, text='Dump text field')
dump_text_field_btn.pack(side='top')
dumping_text = tk.Text(root, height=7, width=40)
dumping_text.pack(side='top')
def create_labels():
for i in range(1, 7):
lbl = tk.Label(label_text_field, width=12, text=f'label {i}')
label_text_field.window_create("insert", window=lbl, padx=8, pady=8)
create_labels_btn['command'] = create_labels
def delete_labels():
for lbl in label_text_field.dump("1.0", "end"):
if lbl[0] =='window' and lbl[1]:
label_text_field.nametowidget(lbl[1]).destroy()
delete_labels_btn['command'] = delete_labels
def dump_text_field():
dumping_text.delete("1.0", "end")
for obj in label_text_field.dump("1.0", "end"):
dumping_text.insert('end', str(obj) + '\n')
dump_text_field_btn['command'] = dump_text_field
root.mainloop()
After creating and deleting my labels. The deleted elements are still visible in the dump output (the widget was succesfully deleted though and the remaining name is only an empty string):
How can I cleanly remove the associated window so that they don’t add up over time?
>Solution :
You need to remove the items from the Text widget using the index returned by .dump(). But you need to remove them in reverse order, otherwise the index will be wrong after removing the first item.
def delete_labels():
for lbl in label_text_field.dump("1.0", "end")[::-1]: # get the items in reverse order
if lbl[0] =='window' and lbl[1]:
label_text_field.nametowidget(lbl[1]).destroy()
label_text_field.delete(lbl[2]) # remove item from text box as well
Actually you can pass window=1 to dump() to return window items only:
def delete_labels():
for lbl in label_text_field.dump("1.0", "end", window=1)[::-1]:
if lbl[1]:
label_text_field.nametowidget(lbl[1]).destroy()
label_text_field.delete(lbl[2])
