Прежде всего, я хочу обратиться к этой части вопроса:
Я полагаю, что tkinter работает на основе перекрытия и не меняет элемент сетки, пока что-то не перекрывается специально.
Я не совсем уверен, что вы подразумеваете под этим, но если это означает, что я думаю, это означает, что это ложное утверждение. tkinter не "работает на основе перекрытия". Если вы уничтожаете виджет, он уничтожается. Неважно, перекрыт он или нет.
Основываясь на крошечном кусочке кода, который вы разместили, основная проблема заключается в том, что вы не помещаете запись и кнопку в рамку. Из-за этого они не уничтожаются при разрушении кадра.
Причина, по которой вы не помещаете виджеты в рамку, заключается в следующей строке:
frame_x[i] = Frame(root).grid(row = 1, column = i)
В python, когда вы делаете x=y().z()
, x
имеет значение z()
. Таким образом, когда вы делаете frame_x[i] = Frame(...).grid(...)
, frame_x[i]
имеет значение .grid(...)
, а .grid(...)
всегда возвращает None . Таким образом, frame_x[i]
будет None
.
Когда вы в следующий раз делаете entry_x[i] = Entry(frame_x[i]).grid(...)
, это то же самое, что и entry_x[i] = Entry(None).grid(...)
. Поскольку мастер Entry
равен None
, он становится дочерним элементом корневого окна.
Итак, первый шаг - отделить создание виджета от макета виджета.
frame_x[i] = Frame(root)
frame_x[i].grid(row = 1, column = i)
Как только вы это сделаете, виджеты Entry
и Button
станут дочерними для фрейма, и вы можете удалить ненужные виджеты, уничтожив фрейм (например: frame_x[i].destroy()
), так как уничтожив виджет также приведет к уничтожению всех дочерних элементов виджета.
Как только вы это сделаете, вы можете уничтожить ненужные виджеты, просто вызвав .destroy()
в кадре. Например, если вы ранее создали 10 групп и теперь вам нужно только 5, вы можете уничтожить остальные и затем удалить их из списка следующим образом:
# assume 'num' contains the number of frames that we want,
# and that it is smaller than the number of items in frames_x
for frame in frames_x[num:]:
frame.destroy()
frames_x = frames_x[:num]
Вот полная рабочая программа для иллюстрации. Введите число и нажмите кнопку. Это создаст столько комбинаций фрейм + запись + кнопка. Введите новый номер, который больше или меньше, и он будет добавлять или удалять виджеты.
Было бы проще, если бы вы использовали классы, но вы специально попросили решение, которое не использует классы. В вашем реальном коде вам, вероятно, также необходимо сохранить виджеты ввода в массиве, чтобы вы могли ссылаться на них позже, но этот пример посвящен созданию виджетов, а не написанию всей вашей программы для вас.
import tkinter as tk
frames_x = [] def create_widgets():
global frames_x
num = int(num_widgets.get())
# if the number is less than the previous number of
# widgets, delete the widgets we no longer want
for frame in frames_x[num:]:
frame.destroy()
frames_x = frames_x[:num]
# if the number is greater than the previous number of
# widgets, create additional widgets
for i in range(len(frames_x), num):
# create new widget
frame = tk.Frame(root, bd=1, relief="raised")
entry = tk.Entry(frame)
button = tk.Button(frame, text="click me")
# pack entry and button in frame
button.pack(side="right")
entry.pack(side="left", fill="x", expand=True)
# grid the frame in the parent
frame.grid(row=i+1, column=0, columnspan=2)
# save the new frame in the array
frames_x.append(frame)
root = tk.Tk() num_widgets = tk.Entry(root) button = tk.Button(root, text="Create widgets", command=create_widgets)
button.grid(row=0, column=1) num_widgets.grid(row=0, column=0, sticky="ew")
root.mainloop()