tkinter:使用 window_create 彻底销毁在 tk.Text 中创建的自动包装小部件

tkinter: cleanly destroy auto-wrapping widgets created in tk.Text with window_create

基于 的回答,我成功创建了自己的小部件,其中标签使用 window_create.

自动包装在 Text 元素中

我还可以使用 nametowidget 销毁这些标签。但是,删除的小部件的 window 元素仍然存在,并由 dump.

返回

这是我的最小可重现示例:

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()

创建和删除我的标签后。删除的元素在 dump 输出中仍然可见(虽然小部件已成功删除,但剩余的名称只是一个空字符串):

如何彻底删除关联的 window,以免它们随着时间的推移而累加?

您需要使用 .dump() 编辑的 return 索引从 Text 小部件中删除项目。但是需要倒序去掉,否则去掉第一项后index会出错

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

实际上你只能传递 window=1dump() 到 return window 项:

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])